From 24426010738781ebe751ae7c7b00f9d04b8f1220 Mon Sep 17 00:00:00 2001 From: Lyncode Date: Wed, 15 Aug 2012 17:00:34 +0100 Subject: [PATCH] OAI 2.0 (a.k.a XOAI) integrated into DSpace 3.0 (squashed) --- dspace-oai/dspace-oai-api/pom.xml | 91 +- .../main/java/org/dspace/app/didl/UUID.java | 136 -- .../java/org/dspace/app/didl/UUIDFactory.java | 50 - .../org/dspace/app/oai/DIDLCrosswalk.java | 239 ---- .../org/dspace/app/oai/DSpaceOAICatalog.java | 933 ------------- .../dspace/app/oai/DSpaceRecordFactory.java | 95 -- .../dspace/app/oai/LoadDSpaceOAIConfig.java | 45 - .../org/dspace/app/oai/METSCrosswalk.java | 88 -- .../org/dspace/app/oai/OAIDCCrosswalk.java | 271 ---- .../org/dspace/app/oai/PluginCrosswalk.java | 169 --- .../java/org/dspace/app/oai/RDFCrosswalk.java | 245 ---- .../org/dspace/app/oai/UKETDDCCrosswalk.java | 701 ---------- .../dspace/xoai/DSpaceOAIDataProvider.java | 173 +++ .../main/java/org/dspace/xoai/app/XOAI.java | 527 ++++++++ .../dspace/xoai/data/DSpaceDatabaseItem.java | 214 +++ .../org/dspace/xoai/data/DSpaceIdentify.java | 148 +++ .../java/org/dspace/xoai/data/DSpaceItem.java | 45 + .../data/DSpaceItemDatabaseRepository.java | 261 ++++ .../xoai/data/DSpaceItemRepository.java | 164 +++ .../xoai/data/DSpaceItemSolrRepository.java | 168 +++ .../java/org/dspace/xoai/data/DSpaceSet.java | 40 + .../dspace/xoai/data/DSpaceSetRepository.java | 236 ++++ .../org/dspace/xoai/data/DSpaceSolrItem.java | 82 ++ .../xoai/exceptions/CompilingException.java | 38 + .../InvalidMetadataFieldException.java | 19 + .../DSpaceAtLeastOneMetadataFilter.java | 257 ++++ .../filter/DSpaceAuthorizationFilter.java | 75 ++ .../org/dspace/xoai/filter/DSpaceFilter.java | 56 + .../filter/DSpaceMetadataExistsFilter.java | 74 ++ .../xoai/filter/DatabaseFilterResult.java | 61 + .../dspace/xoai/filter/DateFromFilter.java | 58 + .../dspace/xoai/filter/DateUntilFilter.java | 59 + .../xoai/filter/DspaceSetSpecFilter.java | 143 ++ .../dspace/xoai/filter/SolrFilterResult.java | 41 + .../data/DSpaceMetadataFilterOperator.java | 17 + .../dspace/xoai/solr/DSpaceSolrSearch.java | 61 + .../dspace/xoai/solr/DSpaceSolrServer.java | 51 + .../solr/exceptions/DSpaceSolrException.java | 42 + .../DSpaceSolrIndexerException.java | 42 + .../exceptions/SolrSearchEmptyException.java | 43 + .../dspace/xoai/util/DSpaceDataConvert.java | 36 + .../java/org/dspace/xoai/util/DateUtils.java | 110 ++ .../java/org/dspace/xoai/util/ItemUtils.java | 311 +++++ .../xoai/util/MetadataFieldManager.java | 106 ++ .../java/org/dspace/xoai/util/URLUtils.java | 35 + .../dspace/xoai/util/XOAICacheManager.java | 367 ++++++ .../dspace/xoai/util/XOAIDatabaseManager.java | 108 ++ dspace-oai/dspace-oai-webapp/pom.xml | 213 ++- .../src/main/webapp/WEB-INF/web.xml | 106 +- .../src/main/webapp/oai2.xsl | 770 ----------- .../src/main/webapp/oai2.xsl.LICENSE | 339 ----- .../src/main/webapp/static/lyncode.png | Bin 0 -> 3749 bytes .../src/main/webapp/static/style.xsl | 1150 +++++++++++++++++ dspace-oai/pom.xml | 57 +- dspace/config/default.context.xml | 5 +- dspace/config/launcher.xml | 20 +- dspace/config/modules/oai.cfg | 117 +- .../modules/oai/metadataFormats/didl.xsl | 132 ++ .../modules/oai/metadataFormats/dim.xsl | 86 ++ .../modules/oai/metadataFormats/etdms.xsl | 116 ++ .../modules/oai/metadataFormats/marc.xsl | 63 + .../modules/oai/metadataFormats/mets.xsl | 303 +++++ .../modules/oai/metadataFormats/mods.xsl | 84 ++ .../modules/oai/metadataFormats/oai_dc.xsl | 91 ++ .../modules/oai/metadataFormats/ore.xsl | 110 ++ .../modules/oai/metadataFormats/qdc.xsl | 345 +++++ .../modules/oai/metadataFormats/rdf.xsl | 105 ++ .../modules/oai/metadataFormats/uketd_dc.xsl | 105 ++ .../modules/oai/metadataFormats/xoai.xsl | 25 + .../modules/oai/transformers/driver.xsl | 78 ++ .../modules/oai/transformers/openaire.xsl | 91 ++ dspace/config/modules/oai/xoai.xml | 259 ++++ dspace/config/oaicat.properties | 52 - dspace/modules/oai/pom.xml | 224 ++-- dspace/modules/pom.xml | 18 +- dspace/pom.xml | 13 +- dspace/solr/oai/conf/admin-extra.html | 31 + dspace/solr/oai/conf/elevate.xml | 36 + dspace/solr/oai/conf/protwords.txt | 21 + dspace/solr/oai/conf/schema.xml | 185 +++ dspace/solr/oai/conf/solrconfig.xml | 1037 +++++++++++++++ dspace/solr/oai/conf/spellings.txt | 2 + dspace/solr/oai/conf/stopwords.txt | 57 + dspace/solr/oai/conf/synonyms.txt | 31 + dspace/solr/oai/conf/xslt/DRI.xsl | 105 ++ dspace/solr/oai/conf/xslt/example.xsl | 132 ++ dspace/solr/oai/conf/xslt/example_atom.xsl | 67 + dspace/solr/oai/conf/xslt/example_rss.xsl | 66 + dspace/solr/oai/conf/xslt/luke.xsl | 337 +++++ dspace/solr/solr.xml | 73 +- dspace/src/main/config/build.xml | 4 + pom.xml | 8 +- 92 files changed, 9973 insertions(+), 4627 deletions(-) delete mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/didl/UUID.java delete mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/didl/UUIDFactory.java delete mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/DIDLCrosswalk.java delete mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/DSpaceOAICatalog.java delete mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/DSpaceRecordFactory.java delete mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/LoadDSpaceOAIConfig.java delete mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/METSCrosswalk.java delete mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/OAIDCCrosswalk.java delete mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/PluginCrosswalk.java delete mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/RDFCrosswalk.java delete mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/UKETDDCCrosswalk.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/DSpaceOAIDataProvider.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/app/XOAI.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceDatabaseItem.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceIdentify.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceItem.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceItemDatabaseRepository.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceItemRepository.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceItemSolrRepository.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceSet.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceSetRepository.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceSolrItem.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/exceptions/CompilingException.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/exceptions/InvalidMetadataFieldException.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DSpaceAtLeastOneMetadataFilter.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DSpaceAuthorizationFilter.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DSpaceFilter.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DSpaceMetadataExistsFilter.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DatabaseFilterResult.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DateFromFilter.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DateUntilFilter.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DspaceSetSpecFilter.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/SolrFilterResult.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/data/DSpaceMetadataFilterOperator.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/DSpaceSolrSearch.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/DSpaceSolrServer.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/exceptions/DSpaceSolrException.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/exceptions/DSpaceSolrIndexerException.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/exceptions/SolrSearchEmptyException.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/DSpaceDataConvert.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/DateUtils.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/ItemUtils.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/MetadataFieldManager.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/URLUtils.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/XOAICacheManager.java create mode 100644 dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/XOAIDatabaseManager.java delete mode 100644 dspace-oai/dspace-oai-webapp/src/main/webapp/oai2.xsl delete mode 100644 dspace-oai/dspace-oai-webapp/src/main/webapp/oai2.xsl.LICENSE create mode 100644 dspace-oai/dspace-oai-webapp/src/main/webapp/static/lyncode.png create mode 100644 dspace-oai/dspace-oai-webapp/src/main/webapp/static/style.xsl create mode 100644 dspace/config/modules/oai/metadataFormats/didl.xsl create mode 100644 dspace/config/modules/oai/metadataFormats/dim.xsl create mode 100644 dspace/config/modules/oai/metadataFormats/etdms.xsl create mode 100644 dspace/config/modules/oai/metadataFormats/marc.xsl create mode 100644 dspace/config/modules/oai/metadataFormats/mets.xsl create mode 100644 dspace/config/modules/oai/metadataFormats/mods.xsl create mode 100644 dspace/config/modules/oai/metadataFormats/oai_dc.xsl create mode 100644 dspace/config/modules/oai/metadataFormats/ore.xsl create mode 100644 dspace/config/modules/oai/metadataFormats/qdc.xsl create mode 100644 dspace/config/modules/oai/metadataFormats/rdf.xsl create mode 100644 dspace/config/modules/oai/metadataFormats/uketd_dc.xsl create mode 100644 dspace/config/modules/oai/metadataFormats/xoai.xsl create mode 100644 dspace/config/modules/oai/transformers/driver.xsl create mode 100644 dspace/config/modules/oai/transformers/openaire.xsl create mode 100644 dspace/config/modules/oai/xoai.xml delete mode 100644 dspace/config/oaicat.properties create mode 100644 dspace/solr/oai/conf/admin-extra.html create mode 100644 dspace/solr/oai/conf/elevate.xml create mode 100644 dspace/solr/oai/conf/protwords.txt create mode 100644 dspace/solr/oai/conf/schema.xml create mode 100644 dspace/solr/oai/conf/solrconfig.xml create mode 100644 dspace/solr/oai/conf/spellings.txt create mode 100644 dspace/solr/oai/conf/stopwords.txt create mode 100644 dspace/solr/oai/conf/synonyms.txt create mode 100644 dspace/solr/oai/conf/xslt/DRI.xsl create mode 100644 dspace/solr/oai/conf/xslt/example.xsl create mode 100644 dspace/solr/oai/conf/xslt/example_atom.xsl create mode 100644 dspace/solr/oai/conf/xslt/example_rss.xsl create mode 100644 dspace/solr/oai/conf/xslt/luke.xsl diff --git a/dspace-oai/dspace-oai-api/pom.xml b/dspace-oai/dspace-oai-api/pom.xml index 189e003853..bc91007d01 100644 --- a/dspace-oai/dspace-oai-api/pom.xml +++ b/dspace-oai/dspace-oai-api/pom.xml @@ -1,40 +1,57 @@ - - 4.0.0 - org.dspace - dspace-oai-api - jar - DSpace OAI :: API and Implementation - Libraries to support DSpace OAI Service Provider Webapplication + + + 4.0.0 + + dspace-oai + org.dspace + 3.0-SNAPSHOT + + dspace-oai-api + DSpace OAI 2.0 :: API and Implementation + + UTF-8 + + XOAI API - - - org.dspace - dspace-oai - 3.0-SNAPSHOT - .. - - - - - org.dspace - dspace-api - - - org.dspace - dspace-api-lang - - - org.dspace - oaicat - - - javax.servlet - servlet-api - provided - - + + + com.lyncode + xoai + 2.2.0 + + + org.dspace + dspace-api + + + org.apache.solr + solr-solrj + 3.3.0 + + + javax.servlet + servlet-api + 2.3 + + + org.slf4j + slf4j-log4j12 + 1.5.6 + + + org.slf4j + slf4j-api + 1.5.6 + + + + + DSpace @ Lyncode + dspace@lyncode.com + Lyncode + http://www.lyncode.com + + diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/didl/UUID.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/didl/UUID.java deleted file mode 100644 index 4decb1a801..0000000000 --- a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/didl/UUID.java +++ /dev/null @@ -1,136 +0,0 @@ -/** - * The contents of this file are subject to the license and copyright - * detailed in the LICENSE and NOTICE files at the root of the source - * tree and available online at - * - * http://www.dspace.org/license/ - */ -package org.dspace.app.didl; - -import java.io.Serializable; -/** - * This class implements UUID version 4. The values for the various fields are - * crypto random values set by the factory class UUIDFactory - * - * Development of this code was part of the aDORe repository project by the - * Research Library of the Los Alamos National Laboratory. - * - * This code is based on the implementation of UUID version 4 (the one that - * uses random/pseudo-random numbers by Ashraf Amrou of the Old Dominion University - * (Aug 14, 2003) - **/ -public final class UUID implements Serializable -{ - private long hi; - private long lo; - - /** - * Construct a Version 4 UUID object from another UUID object - * - * @param uuid - * the UUID to use as a base for the new UUID - **/ - public UUID(UUID uuid) - { - this.hi = uuid.hi; - this.lo = uuid.lo; - } - - /** - * Construct a Version 4 UUID object form the two given long values. - * These values are (pseudo)random numbers (best if crypto quality) - * - * @param _hi - * first long value - * - * @param _lo - * second long value - * - **/ - public UUID(long _hi, long _lo) - { - this.hi = _hi; - this.lo = _lo; - // IETF variant (10)b - lo &= 0x3FFFFFFFFFFFFFFFL; lo |= 0x8000000000000000L; - // set multicast bit (so that it there is no chance it will clash - // with other UUIDs generated based on real IEEE 802 addresses) - lo |= 0x0000800000000000L; - // version 4 (100)b: the one based on random/pseudo-random numbers - hi &= 0xFFFFFFFFFFFF0FFFL; hi |= 0x0000000000004000L; - } - - /** - * Compare UUID objects - * - * @param obj - * the object to compare this UUID against - * - * @return true or false - **/ - public boolean equals(Object obj) - { - if(this == obj) // comparing to myself - { - return true; - } - if(obj instanceof UUID) - { - UUID uuid = (UUID)obj; - return (hi == uuid.hi && lo == uuid.lo); - } - return false; - } - - /** - * Generate a hash for the UUID - * - * @return hash code for the UUID - * - **/ - public int hashCode() - { - return Long.valueOf(hi ^ lo).hashCode(); - } - - - /** - * Obtain a string representation of the UUID object - * - * @return the string representation of this UUID - * - **/ - public String toString() - { - return (/**"urn:uuid:" + **/ - hexDigits(hi >> 32, 4) // time_low: 4 hexOctet (8 hex digits) - + "-" + - hexDigits(hi >> 16, 2) // time_mid: 2 hexOctet (4 hex digits) - + "-" + - hexDigits(hi, 2) // time_high_and_version: 2 hexOctet (4 hex digits) - + "-" + - hexDigits(lo >> 48, 2) // clock_seq_and_reserved: 1 hexOctet (2 hex digits) & clock_seq_low: 1 hexOctet (2 hex digits) - + "-" + - hexDigits(lo, 6)); // node: 6 hexOctet (12 hex digits) - } - - /** - * Obtain the Hex value of a given number of least significant octets - * from a long value as a String - * - * @param lVal - * the long value to retrieve octets from - * - * @param nHexOctets - * number of hex octets to return - * - * @return hex value of least significant octets as a string - * - **/ - private static String hexDigits(long lVal, int nHexOctets) { - long tmp = 1L << (nHexOctets * 2 * 4); // e.g., if nHexOctets is 2, tmp = (1 0000 0000 0000 0000)b & tmp - 1 = (1111 1111 1111 1111)b - long result = lVal & (tmp - 1); // get ride of the uneeded most significant bits - result = tmp | result; // make sure the digit at position (nDigits + 1) equals 1 (to preserve leading zeroes) - return Long.toHexString(result).substring(1); // getride ot the digit at position nDigits + 1 - } -} \ No newline at end of file diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/didl/UUIDFactory.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/didl/UUIDFactory.java deleted file mode 100644 index 237aa3a515..0000000000 --- a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/didl/UUIDFactory.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.app.didl; - -import java.security.SecureRandom; -import java.util.Random; -/** - * Factory class for generating UUID version 4. All what this class does is - * creating UUID version 4 objects using crypto-quality random numbers. - * - * Development of this code was part of the aDORe repository project by the - * Research Library of the Los Alamos National Laboratory. - * - * This code is based on the implementation of UUID version 4 (the one that - * uses random/pseudo-random numbers by Ashraf Amrou of the Old Dominion University - * (Aug 14, 2003) - * - **/ -public final class UUIDFactory -{ - /** Random number generator */ - private Random rand = null; - - /** an instance */ - private static UUIDFactory generator = new UUIDFactory(); - - /** private constructor (Singleton class) */ - private UUIDFactory() - { - // crypto-quality random number generator - rand = new SecureRandom(); - } - - /** - * - * Customers of this class call this method to generete new UUID objects - * - * @return a new UUID object - * - **/ - public static synchronized UUID generateUUID() - { - return new UUID(generator.rand.nextLong(),generator.rand.nextLong()); - } -} \ No newline at end of file diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/DIDLCrosswalk.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/DIDLCrosswalk.java deleted file mode 100644 index 33946f4829..0000000000 --- a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/DIDLCrosswalk.java +++ /dev/null @@ -1,239 +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.oai; - -import java.io.BufferedInputStream; -import java.io.InputStream; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Date; -import java.util.Properties; - -import org.apache.commons.codec.binary.Base64; -import org.apache.log4j.Logger; -import org.dspace.app.didl.UUIDFactory; -import org.dspace.content.Bitstream; -import org.dspace.content.Bundle; -import org.dspace.content.Item; -import org.dspace.core.ConfigurationManager; -import org.dspace.core.Context; -import org.dspace.search.HarvestedItemInfo; -import org.dspace.storage.bitstore.BitstreamStorageManager; - -import ORG.oclc.oai.server.crosswalk.Crosswalk; -import ORG.oclc.oai.server.verb.CannotDisseminateFormatException; -import ORG.oclc.oai.server.verb.ServerVerb; - -/** - * DSpace Item DIDL crosswalk. - * - * Development of this code was part of the aDORe repository project - * by the Research Library of the Los Alamos National Laboratory. - * - * @author Henry Jerez - * @author Los Alamos National Laboratory - */ - -public class DIDLCrosswalk extends Crosswalk -{ - private static final Logger log = Logger.getLogger(DIDLCrosswalk.class); - - /** default value if no oai.didl.maxresponse property is defined */ - public static final int MAXRESPONSE_INLINE_BITSTREAM = 0; - - /** another crosswalk that will be used to generate the metadata section */ - private Crosswalk metadataCrosswalk; - - public DIDLCrosswalk(Properties properties) - { - super("urn:mpeg:mpeg21:2002:02-DIDL-NS http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-21_schema_files/did/didl.xsd "); - - // FIXME this should be injected from the configuration... - // but it is better than duplicate the OAIDCCrosswalk code! - metadataCrosswalk = new OAIDCCrosswalk(properties); - } - - - public boolean isAvailableFor(Object nativeItem) - { - // We have DC for everything - return true; - } - - - public String createMetadata(Object nativeItem) - throws CannotDisseminateFormatException - { - Item item = ((HarvestedItemInfo) nativeItem).item; - - StringBuffer metadata = new StringBuffer(); - String itemhandle=item.getHandle(); - String strMaxSize = ConfigurationManager.getProperty("oai", "didl.maxresponse"); - int maxsize = MAXRESPONSE_INLINE_BITSTREAM; - if (strMaxSize != null) - { - maxsize = Integer.parseInt(strMaxSize); - } - - String currdate=ServerVerb.createResponseDate(new Date()); - - metadata.append("") - .append ("") - .append ("") - .append (currdate) - .append (" " ) - .append(""); - metadata.append("") - .append("") - .append("").append("urn:hdl:").append(itemhandle) - .append("") - .append("") - .append(""); - metadata.append("") - .append(""); - - // delegate the metadata section to another crosswalk - metadata.append(metadataCrosswalk.createMetadata(nativeItem)); - - metadata - .append("") - .append(""); - - /**putfirst item here**/ - - - //**CYCLE HERE!!!!**// - - try - { - Bundle[] bundles= item.getBundles("ORIGINAL"); - - if (bundles.length != 0) - { - /**cycle bundles**/ - for (int i = 0; i < bundles.length; i++) - { - int flag=0; - Bitstream[] bitstreams = bundles[i].getBitstreams(); - - /**cycle bitstreams**/ - for (int k = 0; k < bitstreams.length ; k++) - { - // Skip internal types - if (!bitstreams[k].getFormat().isInternal()) - { - if (flag==0) - { - flag=1; - } - - metadata.append(""); - - if (bitstreams[k].getSize()> maxsize) - { - metadata.append(""); - metadata.append(""); - } - else - { - try - { - metadata.append(""); - - /* - * Assume that size of in-line bitstreams will always be - * smaller than MAXINT bytes - */ - int intSize = (int) bitstreams[k].getSize(); - - byte[] buffer = new byte[intSize]; - - Context contextl= new Context(); - InputStream is = BitstreamStorageManager.retrieve(contextl,bitstreams[k].getID()); - BufferedInputStream bis = new BufferedInputStream(is); - try - { - bis.read(buffer); - } - finally - { - if (bis != null) - { - try - { - bis.close(); - } - catch (IOException ioe) - { - } - } - - if (is != null) - { - try - { - is.close(); - } - catch (IOException ioe) - { - } - } - } - - contextl.complete(); - - String encoding = new String(Base64.encodeBase64(buffer), "ASCII"); - metadata.append(encoding); - } - catch (Exception ex) - { - log.error("Error creating resource didl", ex); - - metadata.append(""); - } - - metadata.append(""); - } - metadata.append(""); - } - /*end bitstream cycle*/ - } - /*end bundle cycle*/ - } - } - } - catch (SQLException sqle) - { - System.err.println("Caught exception:"+sqle.getCause()); - log.error("Database error", sqle); - } - - //**END CYCLE HERE **// - - metadata.append("") - .append(""); - - return metadata.toString(); - } -} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/DSpaceOAICatalog.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/DSpaceOAICatalog.java deleted file mode 100644 index b6d39bb4bd..0000000000 --- a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/DSpaceOAICatalog.java +++ /dev/null @@ -1,933 +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.oai; - -import java.sql.SQLException; -import java.text.ParseException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Properties; -import java.util.StringTokenizer; -import java.util.Vector; - -import org.apache.log4j.Logger; -import org.dspace.authorize.AuthorizeManager; -import org.dspace.content.Collection; -import org.dspace.content.Community; -import org.dspace.content.DSpaceObject; -import org.dspace.core.ConfigurationManager; -import org.dspace.core.Constants; -import org.dspace.core.Context; -import org.dspace.core.LogManager; -import org.dspace.core.Utils; -import org.dspace.handle.HandleManager; -import org.dspace.search.Harvest; -import org.dspace.search.HarvestedItemInfo; -import org.dspace.eperson.Group; - -import ORG.oclc.oai.server.catalog.AbstractCatalog; -import ORG.oclc.oai.server.verb.BadArgumentException; -import ORG.oclc.oai.server.verb.BadResumptionTokenException; -import ORG.oclc.oai.server.verb.CannotDisseminateFormatException; -import ORG.oclc.oai.server.verb.IdDoesNotExistException; -import ORG.oclc.oai.server.verb.NoItemsMatchException; -import ORG.oclc.oai.server.verb.NoMetadataFormatsException; -import ORG.oclc.oai.server.verb.NoSetHierarchyException; -import ORG.oclc.oai.server.verb.OAIInternalServerError; - -/** - * This class extends OAICat's AbstractCatalog base class to allow - * harvesting of the metadata in DSpace via OAI-PMH 2.0. - * - * FIXME: Some CNRI Handle-specific stuff in here. Anyone wanting to use - * something else will need to update this code, too. Sorry about that. - * - * @author Robert Tansley - * @version $Revision$ - */ -public class DSpaceOAICatalog extends AbstractCatalog -{ - /** log4j logger */ - private static Logger log = Logger.getLogger(DSpaceOAICatalog.class); - - /** Prefix that all our OAI identifiers have */ - public static final String OAI_ID_PREFIX = "oai:" + ConfigurationManager.getProperty("dspace.hostname") + ":"; - - /** Maximum number of records returned by one request */ - private final int MAX_RECORDS = ConfigurationManager.getIntProperty("oai","response.max-records", 100); - - public DSpaceOAICatalog(Properties properties) - { - // Don't need to do anything - } - - /** - * Retrieve a list of schemaLocation values associated with the specified - * identifier. - * - * @param identifier - * the OAI identifier - * @return a Vector containing schemaLocation Strings - * @exception OAIInternalServerError - * signals an http status code 500 problem - * @exception IdDoesNotExistException - * the specified identifier can't be found - * @exception NoMetadataFormatsException - * the specified identifier was found but the item is flagged - * as deleted and thus no schemaLocations (i.e. - * metadataFormats) can be produced. - */ - public Vector getSchemaLocations(String identifier) - throws OAIInternalServerError, IdDoesNotExistException, - NoMetadataFormatsException - { - log.info(LogManager.getHeader(null, "oai_request", - "verb=getSchemaLocations,identifier=" - + ((identifier == null) ? "null" : identifier))); - - HarvestedItemInfo itemInfo = null; - Context context = null; - - // Get the item from the DB - try - { - context = new Context(); - - // All valid identifiers have the "oai:hostname:" prefix - if (identifier != null && identifier.startsWith(OAI_ID_PREFIX)) - { - itemInfo = Harvest.getSingle(context, identifier - .substring(OAI_ID_PREFIX.length()), // Strip prefix to - // get raw handle - false); - } - } - catch (SQLException se) - { - // Log the error - log.warn(LogManager.getHeader(context, "database_error", ""), se); - - // Stack trace loss as OAI Exception does not support cause - throw new OAIInternalServerError(se.toString()); - } - finally - { - if (context != null) - { - context.abort(); - } - } - - if (itemInfo == null) - { - throw new IdDoesNotExistException(identifier); - } - else - { - if (itemInfo.withdrawn) - { - throw new NoMetadataFormatsException(); - } - else - { - return getRecordFactory().getSchemaLocations(itemInfo); - } - } - } - - /** - * Retrieve a list of identifiers that satisfy the specified criteria - * - * @param from - * beginning date using the proper granularity - * @param until - * ending date using the proper granularity - * @param set - * the set name or null if no such limit is requested - * @param metadataPrefix - * the OAI metadataPrefix or null if no such limit is requested - * @return a Map object containing entries for "headers" and "identifiers" - * Iterators (both containing Strings) as well as an optional - * "resumptionMap" Map. It may seem strange for the map to include - * both "headers" and "identifiers" since the identifiers can be - * obtained from the headers. This may be true, but - * AbstractCatalog.listRecords() can operate quicker if it doesn't - * need to parse identifiers from the XML headers itself. Better - * still, do like I do below and override - * AbstractCatalog.listRecords(). AbstractCatalog.listRecords() is - * relatively inefficient because given the list of identifiers, it - * must call getRecord() individually for each as it constructs its - * response. It's much more efficient to construct the entire - * response in one fell swoop by overriding listRecords() as I've - * done here. - * @exception OAIInternalServerError - * signals an http status code 500 problem - * @exception NoSetHierarchyException - * the repository doesn't support sets. - * @exception CannotDisseminateFormatException - * the metadata format specified is not supported by your - * repository. - */ - public Map listIdentifiers(String from, String until, String set, - String metadataPrefix) throws OAIInternalServerError, - NoSetHierarchyException, NoItemsMatchException, - CannotDisseminateFormatException, BadArgumentException - { - log - .info(LogManager.getHeader(null, "oai_request", - "verb=listIdentifiers,from=" - + ((from == null) ? "null" : from) - + ",until=" - + ((until == null) ? "null" : until) - + ",set=" - + ((set == null) ? "null" : set) - + ",metadataPrefix=" - + ((metadataPrefix == null) ? "null" - : metadataPrefix))); - - // We can produce oai_dc and simple DC for all items, so just return IDs - Context context = null; - - // Lists to put results in - List headers = new LinkedList(); - List identifiers = new LinkedList(); - - try - { - context = new Context(); - - // Get the relevant OAIItemInfo objects to make headers - DSpaceObject scope = resolveSet(context, set); - boolean includeAll = ConfigurationManager.getBooleanProperty("oai", "harvest.includerestricted.oai", true); - // Warning: In large repositories, setting harvest.includerestricted.oai to false may cause - // performance problems as all items will need to have their authorization permissions checked, - // but because we haven't implemented resumption tokens in ListIdentifiers, ALL items will - // need checking whenever a ListIdentifiers request is made. - List itemInfos = Harvest.harvest(context, scope, from, until, 0, 0, // Everything - // for - // now - !includeAll, true, true, includeAll); - - // No Item objects, but we need to know collections they're in and - // withdrawn items - if (itemInfos.size() == 0) - { - log.info(LogManager.getHeader(null, "oai_error", - "no_items_match")); - throw new NoItemsMatchException(); - } - - // Build up lists of headers and identifiers - Iterator i = itemInfos.iterator(); - - while (i.hasNext()) - { - HarvestedItemInfo itemInfo = i.next(); - - String[] header = getRecordFactory().createHeader(itemInfo); - - headers.add(header[0]); - identifiers.add(header[1]); - } - } - catch (SQLException se) - { - // Log the error - log.warn(LogManager.getHeader(context, "database_error", ""), se); - - // Stack trace loss as OAI Exception does not support cause - throw new OAIInternalServerError(se.toString()); - } - catch (ParseException pe) - { - // Stack trace loss as OAI Exception does not support cause - throw new OAIInternalServerError(pe.toString()); - } - finally - { - if (context != null) - { - context.abort(); - } - } - - // Put results in form needed to return - Map> results = new HashMap>(); - results.put("headers", headers.iterator()); - results.put("identifiers", identifiers.iterator()); - - return results; - } - - /** - * Retrieve the next set of identifiers associated with the resumptionToken - * - * @param resumptionToken - * implementation-dependent format taken from the previous - * listIdentifiers() Map result. - * @return a Map object containing entries for "headers" and "identifiers" - * Iterators (both containing Strings) as well as an optional - * "resumptionMap" Map. - * @exception BadResumptionTokenException - * the value of the resumptionToken is invalid or expired. - * @exception OAIInternalServerError - * signals an http status code 500 problem - */ - public Map listIdentifiers(String resumptionToken) - throws BadResumptionTokenException, OAIInternalServerError - { - // Resumption tokens not yet supported - throw new BadResumptionTokenException(); - } - - /** - * Retrieve the specified metadata for the specified identifier - * - * @param identifier - * the OAI identifier - * @param metadataPrefix - * the OAI metadataPrefix - * @return the portion of the XML response. - * @exception OAIInternalServerError - * signals an http status code 500 problem - * @exception CannotDisseminateFormatException - * the metadataPrefix is not supported by the item. - * @exception IdDoesNotExistException - * the identifier wasn't found - */ - public String getRecord(String identifier, String metadataPrefix) - throws OAIInternalServerError, CannotDisseminateFormatException, - IdDoesNotExistException - { - log - .info(LogManager.getHeader(null, "oai_request", - "verb=getRecord,identifier=" - + ((identifier == null) ? "null" : identifier) - + ",metadataPrefix=" - + ((metadataPrefix == null) ? "null" - : metadataPrefix))); - - Context context = null; - String record = null; - HarvestedItemInfo itemInfo = null; - - // First get the item from the DB - try - { - // Valid IDs start with oai:hostname: - if (identifier != null && identifier.startsWith(OAI_ID_PREFIX)) - { - context = new Context(); - - /* - * Try and get the item. the .substring() is to strip the - * oai:(hostname): prefix to get the raw handle - */ - itemInfo = Harvest.getSingle(context, identifier - .substring(OAI_ID_PREFIX.length()), true); - } - - if (itemInfo == null) - { - log.info(LogManager.getHeader(null, "oai_error", - "id_does_not_exist")); - throw new IdDoesNotExistException(identifier); - } - - boolean includeAll = ConfigurationManager.getBooleanProperty("oai", "harvest.includerestricted.oai", true); - - if (!includeAll) - { - Group[] authorizedGroups = AuthorizeManager.getAuthorizedGroups(context, itemInfo.item, Constants.READ); - boolean authorized = false; - for (int i = 0; i < authorizedGroups.length; i++) - { - if ((authorizedGroups[i].getID() == 0) && (!authorized)) - { - authorized = true; - } - } - - if (!authorized) - { - log.info(LogManager.getHeader(null, "oai_error", - "id_not_accessible")); - throw new IdDoesNotExistException(identifier); - } - } - - String schemaURL = getCrosswalks().getSchemaURL(metadataPrefix); - - if (schemaURL == null) - { - log.info(LogManager.getHeader(null, "oai_error", - "cannot_disseminate_format")); - throw new CannotDisseminateFormatException(metadataPrefix); - } - - record = getRecordFactory().create(itemInfo, schemaURL, - metadataPrefix); - } - catch (SQLException se) - { - // Log the error - log.warn(LogManager.getHeader(context, "database_error", ""), se); - - // Stack trace loss as OAI Exception does not support cause - throw new OAIInternalServerError(se.toString()); - } - finally - { - if (context != null) - { - context.abort(); - } - } - - return record; - } - - /** - * Retrieve a list of records that satisfy the specified criteria. Note, - * though, that unlike the other OAI verb type methods implemented here, - * both of the listRecords methods are already implemented in - * AbstractCatalog rather than abstracted. This is because it is possible to - * implement ListRecords as a combination of ListIdentifiers and GetRecord - * combinations. Nevertheless, I suggest that you override both the - * AbstractCatalog.listRecords methods here since it will probably improve - * the performance if you create the response in one fell swoop rather than - * construct it one GetRecord at a time. - * - * @param from - * beginning date using the proper granularity - * @param until - * ending date using the proper granularity - * @param set - * the set name or null if no such limit is requested - * @param metadataPrefix - * the OAI metadataPrefix or null if no such limit is requested - * @return a Map object containing entries for a "records" Iterator object - * (containing XML Strings) and an optional - * "resumptionMap" Map. - * @exception OAIInternalServerError - * signals an http status code 500 problem - * @exception NoSetHierarchyException - * The repository doesn't support sets. - * @exception CannotDisseminateFormatException - * the metadataPrefix isn't supported by the item. - */ - public Map listRecords(String from, String until, String set, - String metadataPrefix) throws OAIInternalServerError, - NoSetHierarchyException, CannotDisseminateFormatException, - NoItemsMatchException, BadArgumentException - { - log - .info(LogManager.getHeader(null, "oai_request", - "verb=listRecords,from=" - + ((from == null) ? "null" : from) - + ",until=" - + ((until == null) ? "null" : until) - + ",set=" - + ((set == null) ? "null" : set) - + ",metadataPrefix=" - + ((metadataPrefix == null) ? "null" - : metadataPrefix))); - - Map m = doRecordHarvest(from, until, set, metadataPrefix, 0); - - // Null means bad metadata prefix - if (m == null) - { - log.info(LogManager.getHeader(null, "oai_error", - "cannot_disseminate_format")); - throw new CannotDisseminateFormatException(metadataPrefix); - } - - // If there were zero results, return the appropriate error - Iterator i = (Iterator) m.get("records"); - - if ((i == null) || !i.hasNext()) - { - log.info(LogManager.getHeader(null, "oai_error", "no_items_match")); - throw new NoItemsMatchException(); - } - - return m; - } - - /** - * Retrieve the next set of records associated with the resumptionToken - * - * @param resumptionToken - * implementation-dependent format taken from the previous - * listRecords() Map result. - * @return a Map object containing entries for "headers" and "identifiers" - * Iterators (both containing Strings) as well as an optional - * "resumptionMap" Map. - * @exception OAIInternalServerError - * signals an http status code 500 problem - * @exception BadResumptionTokenException - * the value of the resumptionToken argument is invalid or - * expired. - */ - public Map listRecords(String resumptionToken) - throws BadResumptionTokenException, OAIInternalServerError - { - log.info(LogManager.getHeader(null, "oai_request", - "verb=listRecords,resumptionToken=" + resumptionToken)); - - /* - * FIXME: This may return zero records if the previous harvest returned - * a number of records that's an exact multiple of MAX_RECORDS. I hope - * that's OK. - */ - Object[] params = decodeResumptionToken(resumptionToken); - Integer offset = (Integer) params[4]; - - Map m = null; - - /* - * We catch BadArgumentExceptions here, because doRecordHarvest() throws - * BadArgumentExcpetions when the set spec is bad. set spec bad == bad - * resumption token. - */ - try - { - m = doRecordHarvest((String) params[0], (String) params[1], - (String) params[2], (String) params[3], offset.intValue()); - } - catch (BadArgumentException bae) - { - m = null; - } - - // null result means a problem -> bad resumption token - if (m == null) - { - log.info(LogManager.getHeader(null, "oai_error", - "bad_resumption_token")); - throw new BadResumptionTokenException(); - } - - return m; - } - - /** - * Method to do the actual harvest of records - * - * @param from - * OAI 'from' parameter - * @param until - * OAI 'until' parameter - * @param set - * OAI 'set' parameter - * @param metadataPrefix - * OAI 'metadataPrefix' parameter - * @param offset - * where to start this harvest - * - * @return the Map for listRecords to return, or null if the metadataPrefix - * is invalid - */ - private Map doRecordHarvest(String from, String until, String set, - String metadataPrefix, int offset) throws OAIInternalServerError, - BadArgumentException - { - Context context = null; - String schemaURL = getCrosswalks().getSchemaURL(metadataPrefix); - Map results = new HashMap(); - - if (schemaURL == null) - { - return null; - } - - // List to put results in - List records = new LinkedList(); - - try - { - context = new Context(); - - // Get the relevant HarvestedItemInfo objects to make headers - DSpaceObject scope = resolveSet(context, set); - boolean includeAll = ConfigurationManager.getBooleanProperty("oai", "harvest.includerestricted.oai", true); - List itemInfos = Harvest.harvest(context, scope, from, until, - offset, MAX_RECORDS, // Limit amount returned from one - // request - true, true, true, includeAll); // Need items, containers + withdrawals - - // Build list of XML records from item info objects - int ignore = 0; - for (HarvestedItemInfo itemInfo : itemInfos) - { - try - { - String recordXML = getRecordFactory().create(itemInfo, schemaURL, metadataPrefix); - records.add(recordXML); - } - catch (CannotDisseminateFormatException cdfe) - { - /* - * FIXME: I've a feeling a - * "CannotDisseminateFormatException" should be discarded - * here - it's OK if some records in the requested date - * range don't have the requested metadata format available. - * I'll just log it for now. - */ - ignore++; - if (log.isDebugEnabled()) - { - log.debug(LogManager.getHeader(context, "oai_warning", - "Couldn't disseminate " + metadataPrefix - + " for " + itemInfo.handle)); - } - } - } - - // Put results in form needed to return - results.put("records", records.iterator()); - - log.info(LogManager.getHeader(context, "oai_harvest", "results=" + records.size() + ", ignore=" + ignore)); - - // If we have MAX_RECORDS records, we need to provide a resumption - // token - if ((records.size() + ignore) >= MAX_RECORDS) - { - String resumptionToken = makeResumptionToken(from, until, set, - metadataPrefix, offset + MAX_RECORDS); - - if (log.isDebugEnabled()) - { - log.debug(LogManager - .getHeader(context, "made_resumption_token", - "token=" + resumptionToken)); - } - - results.put("resumptionMap", getResumptionMap(resumptionToken)); - - //results.put("resumptionToken", resumptionToken); - } - } - catch (SQLException se) - { - // Log the error - log.warn(LogManager.getHeader(context, "database_error", ""), se); - - // Stack trace loss as OAI Exception does not support cause - throw new OAIInternalServerError(se.toString()); - } - catch (ParseException pe) - { - // Stack trace loss as OAI Exception does not support cause - throw new OAIInternalServerError(pe.toString()); - } - finally - { - if (context != null) - { - context.abort(); - } - } - - return results; - } - - /** - * Retrieve a list of sets that satisfy the specified criteria - * - * @return a Map object containing "sets" Iterator object (contains - * XML Strings) as well as an optional resumptionMap Map. - * @exception NoSetHierarchyException - * signals an http status code 400 problem - * @exception OAIInternalServerError - * signals an http status code 500 problem - */ - public Map listSets() throws NoSetHierarchyException, - OAIInternalServerError - { - log.info(LogManager.getHeader(null, "oai_request", "verb=listSets")); - - Context context = null; - - // List to put results in - List sets = new LinkedList(); - - try - { - context = new Context(); - - Collection[] allCols = Collection.findAll(context); - StringBuffer spec = null; - for (int i = 0; i < allCols.length; i++) - { - spec = new StringBuffer("hdl_"); - spec.append(allCols[i].getHandle().replace('/', '_')); - spec.append(""); - String collName = allCols[i].getMetadata("name"); - if(collName != null) - { - spec.append(""); - spec.append(Utils.addEntities(collName)); - spec.append(""); - } - else - { - spec.append(""); - // Warn that there is an error of a null set name - log.info(LogManager.getHeader(null, "oai_error", - "null_set_name_for_set_id_" + allCols[i].getHandle())); - } - spec.append(""); - sets.add(spec.toString()); - } - - Community[] allComs = Community.findAll(context); - for (int i = 0; i < allComs.length; i++) - { - spec = new StringBuffer("hdl_"); - spec.append(allComs[i].getHandle().replace('/', '_')); - spec.append(""); - String commName = allComs[i].getMetadata("name"); - if(commName != null) - { - spec.append(""); - spec.append(Utils.addEntities(commName)); - spec.append(""); - } - else - { - spec.append(""); - // Warn that there is an error of a null set name - log.info(LogManager.getHeader(null, "oai_error", - "null_set_name_for_set_id_" + allComs[i].getHandle())); - } - spec.append(""); - sets.add(spec.toString()); - } - } - catch (SQLException se) - { - // Log the error - log.warn(LogManager.getHeader(context, "database_error", ""), se); - - // Stack trace loss as OAI Exception does not support cause - throw new OAIInternalServerError(se.toString()); - } - finally - { - if (context != null) - { - context.abort(); - } - } - - // Put results in form needed to return - Map> results = new HashMap>(); - results.put("sets", sets.iterator()); - - return results; - } - - /** - * Retrieve the next set of sets associated with the resumptionToken - * - * @param resumptionToken - * implementation-dependent format taken from the previous - * listSets() Map result. - * @return a Map object containing "sets" Iterator object (contains - * XML Strings) as well as an optional resumptionMap Map. - * @exception BadResumptionTokenException - * the value of the resumptionToken is invalid or expired. - * @exception OAIInternalServerError - * signals an http status code 500 problem - */ - public Map listSets(String resumptionToken) - throws BadResumptionTokenException, OAIInternalServerError - { - // Resumption tokens not yet supported - throw new BadResumptionTokenException(); - } - - /** - * close the repository - */ - public void close() - { - } - - // ****************************************** - // Internal DSpace utility methods below here - // ****************************************** - - /** - * Get the community or collection signified by a set spec - * - * @param context - * DSpace context object - * @param set - * OAI set spec - * @return the corresponding community or collection, or null if no set - * provided - */ - private DSpaceObject resolveSet(Context context, String set) - throws SQLException, BadArgumentException - { - if (set == null) - { - return null; - } - - DSpaceObject o = null; - - /* - * set specs are in form hdl_123.456_789 corresponding to - * hdl:123.456/789 - */ - if (set.startsWith("hdl_")) - { - // Looks OK so far... turn second _ into / - String handle = set.substring(4).replace('_', '/'); - o = HandleManager.resolveToObject(context, handle); - } - - // If it corresponds to a collection or a community, that's the set we - // want - if ((o != null) && - ((o instanceof Collection) || (o instanceof Community))) - { - return o; - } - - // Handle is either non-existent, or corresponds to a non-collection - // Either way, a bad set spec, ergo a bad argument - throw new BadArgumentException(); - } - - /** - * Create a resumption token. The relevant parameters for the harvest are - * put in a - * - * @param from - * OAI 'from' parameter - * @param until - * OAI 'until' parameter - * @param set - * OAI 'set' parameter - * @param prefix - * OAI 'metadataPrefix' parameter - * @param offset - * where to start the next harvest - * - * @return the appropriate resumption token - */ - private String makeResumptionToken(String from, String until, String set, - String prefix, int offset) - { - StringBuffer token = new StringBuffer(); - - if (from != null) - { - token.append(from); - } - - token.append("/"); - - if (until != null) - { - token.append(until); - } - - token.append("/"); - - if (set != null) - { - token.append(set); - } - - token.append("/"); - - if (prefix != null) - { - token.append(prefix); - } - - token.append("/"); - token.append(String.valueOf(offset)); - - return (token.toString()); - } - - /** - * Get the information out of a resumption token - * - * @param token - * the resumption token - * @return a 5-long array of Objects; 4 Strings (from, until, set, prefix) - * and an Integer (the offset) - */ - private Object[] decodeResumptionToken(String token) - throws BadResumptionTokenException - { - Object[] obj = new Object[5]; - StringTokenizer st = new StringTokenizer(token, "/", true); - - try - { - // Extract from, until, set, prefix - for (int i = 0; i < 4; i++) - { - if (!st.hasMoreTokens()) - { - throw new BadResumptionTokenException(); - } - - String s = st.nextToken(); - - // If this value is a delimiter /, we have no value for this - // part of the resumption token. - if (s.equals("/")) - { - obj[i] = null; - } - else - { - obj[i] = s; - - // Skip the delimiter - st.nextToken(); - } - - log.debug("is: " + (String) obj[i]); - } - - if (!st.hasMoreTokens()) - { - throw new BadResumptionTokenException(); - } - - obj[4] = Integer.valueOf(st.nextToken()); - } - catch (NumberFormatException nfe) - { - // Stack trace loss as OAI Exception does not support cause - throw new BadResumptionTokenException(); - } - catch (NoSuchElementException nsee) - { - // Stack trace loss as OAI Exception does not support cause - throw new BadResumptionTokenException(); - } - - return obj; - } -} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/DSpaceRecordFactory.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/DSpaceRecordFactory.java deleted file mode 100644 index b78facf93c..0000000000 --- a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/DSpaceRecordFactory.java +++ /dev/null @@ -1,95 +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.oai; - -import java.util.Date; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Properties; - -import org.dspace.content.DCDate; -import org.dspace.search.HarvestedItemInfo; - -import ORG.oclc.oai.server.catalog.RecordFactory; -import ORG.oclc.oai.server.verb.CannotDisseminateFormatException; - -/** - * Implementation of the OAICat RecordFactory base class for DSpace items. - * - * @author Robert Tansley - * @version $Revision$ - */ -public class DSpaceRecordFactory extends RecordFactory -{ - public DSpaceRecordFactory(Properties properties) - { - // We don't use the OAICat properties; pass on up - super(properties); - } - - public String fromOAIIdentifier(String identifier) - { - // Our local identifier is actually the same as the OAI one (the Handle) - return identifier; - } - - public String quickCreate(Object nativeItem, String schemaURL, - String metadataPrefix) throws IllegalArgumentException, - CannotDisseminateFormatException - { - // Not supported - return null; - } - - public String getOAIIdentifier(Object nativeItem) - { - String h = DSpaceOAICatalog.OAI_ID_PREFIX - + ((HarvestedItemInfo) nativeItem).handle; - - return h; - } - - public String getDatestamp(Object nativeItem) - { - Date d = ((HarvestedItemInfo) nativeItem).datestamp; - - // Return as ISO8601 - return new DCDate(d).toString(); - } - - public Iterator getSetSpecs(Object nativeItem) - { - HarvestedItemInfo hii = (HarvestedItemInfo) nativeItem; - Iterator i = hii.collectionHandles.iterator(); - List setSpecs = new LinkedList(); - - // Convert the DB Handle string 123.456/789 to the OAI-friendly - // hdl_123.456/789 - while (i.hasNext()) - { - String handle = "hdl_" + i.next(); - setSpecs.add(handle.replace('/', '_')); - } - - return setSpecs.iterator(); - } - - public boolean isDeleted(Object nativeItem) - { - HarvestedItemInfo hii = (HarvestedItemInfo) nativeItem; - - return hii.withdrawn; - } - - public Iterator getAbouts(Object nativeItem) - { - // Nothing in the about section for now - return new LinkedList().iterator(); - } -} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/LoadDSpaceOAIConfig.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/LoadDSpaceOAIConfig.java deleted file mode 100644 index f2044925f8..0000000000 --- a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/LoadDSpaceOAIConfig.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * The contents of this file are subject to the license and copyright - * detailed in the LICENSE and NOTICE files at the root of the source - * tree and available online at - * - * http://www.dspace.org/license/ - */ -package org.dspace.app.oai; - -import javax.servlet.http.HttpServlet; - -import org.dspace.core.ConfigurationManager; - -/** - * Simple servlet to load in DSpace and log4j configurations. Should always be - * started up before other servlets (use ) - * - * This class holds code to be removed in the next version of the DSpace XMLUI, - * it is now managed by a Shared Context Listener inthe dspace-api project. - * - * It is deprecated, rather than removed to maintain backward compatibility for - * local DSpace 1.5.x customized overlays. - * - * TODO: Remove in trunk - * - * @deprecated Use Servlet Context Listener provided in dspace-api (remove in > - * 1.5.x) - * - * @author Robert Tansley - * @version $Revision$ - */ -public class LoadDSpaceOAIConfig extends HttpServlet -{ - public void init() - { - if(!ConfigurationManager.isConfigured()) - { - // Get config parameter - String config = getServletContext().getInitParameter("dspace-config"); - - // Load in DSpace config - ConfigurationManager.loadConfig(config); - } - } -} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/METSCrosswalk.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/METSCrosswalk.java deleted file mode 100644 index aa1fae6984..0000000000 --- a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/METSCrosswalk.java +++ /dev/null @@ -1,88 +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.oai; - -import java.util.Properties; - -import org.apache.log4j.Logger; - -import ORG.oclc.oai.server.crosswalk.Crosswalk; -import ORG.oclc.oai.server.verb.CannotDisseminateFormatException; -import org.dspace.content.crosswalk.DisseminationCrosswalk; -import org.dspace.core.PluginManager; -import org.dspace.search.HarvestedItemInfo; - -import org.jdom.Element; -import org.jdom.output.Format; -import org.jdom.output.XMLOutputter; - -/** - * OAICat crosswalk to allow METS to be harvested. - * - * No security or privacy measures in place. - * - * @author Li XiaoYu (Rita) - * @author Robert Tansley - * @author Tim Donohue (rewrite to use METS DisseminationCrosswalk) - */ -public class METSCrosswalk extends Crosswalk -{ - private static final Logger log = Logger.getLogger(METSCrosswalk.class); - - // JDOM xml output writer - indented format for readability. - private static XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat()); - - public METSCrosswalk(Properties properties) - { - super( - "http://www.loc.gov/METS/ http://www.loc.gov/standards/mets/mets.xsd"); - } - - @Override - public boolean isAvailableFor(Object nativeItem) - { - // We have METS for everything - return true; - } - - @Override - public String createMetadata(Object nativeItem) - throws CannotDisseminateFormatException - { - HarvestedItemInfo hii = (HarvestedItemInfo) nativeItem; - - try - { - //Get a reference to our DSpace METS DisseminationCrosswalk - // (likely this is org.dspace.content.crosswalk.METSDisseminationCrosswalk) - DisseminationCrosswalk xwalk = (DisseminationCrosswalk)PluginManager. - getNamedPlugin(DisseminationCrosswalk.class, "METS"); - - //if no crosswalk found, thrown an error - if(xwalk==null) - throw new CannotDisseminateFormatException("DSpace cannot disseminate METS format, as no DisseminationCrosswalk is configured which supports 'METS'"); - - if(xwalk.canDisseminate(hii.item)) - { - //disseminate the object to METS - Element rootElement = xwalk.disseminateElement(hii.item); - - //Return XML results as a formatted String - return outputter.outputString(rootElement); - } - else - return null; // cannot disseminate this type of object - } - catch (Exception e) - { - log.error("OAI-PMH METSCrosswalk error", e); - return null; - } - - } -} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/OAIDCCrosswalk.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/OAIDCCrosswalk.java deleted file mode 100644 index e44b41b849..0000000000 --- a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/OAIDCCrosswalk.java +++ /dev/null @@ -1,271 +0,0 @@ -/** - * The contents of this file are subject to the license and copyright - * detailed in the LICENSE and NOTICE files at the root of the source - * tree and available online at - * - * http://www.dspace.org/license/ - */ -package org.dspace.app.oai; - -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.sql.SQLException; - -import org.dspace.app.util.MetadataExposure; -import org.dspace.content.DCValue; -import org.dspace.content.Item; -import org.dspace.content.crosswalk.IConverter; -import org.dspace.search.HarvestedItemInfo; -import org.dspace.core.ConfigurationManager; -import org.dspace.core.PluginManager; -import org.dspace.core.LogManager; -import org.apache.log4j.Logger; - -import ORG.oclc.oai.server.crosswalk.Crosswalk; -import ORG.oclc.oai.server.verb.CannotDisseminateFormatException; - -/** - * OAI_DC Crosswalk implementation based on oaidc.properties file. All metadata - * included in the oaidc.properties file will be mapped on a valid oai_dc - * element, invalid oai_dc element will be not used. It is possible specify for - * any metadata a converter {@link org.dspace.content.crosswalk.IConverter} - * to manipulate the metadata value before that it will be dissemite in OAI_DC. - * - * @author Robert Tansley - * @author Andrea Bollini - * @version $Revision$ - */ -public class OAIDCCrosswalk extends Crosswalk -{ - // Pattern containing all the characters we want to filter out / replace - // converting a String to xml - private static final Pattern invalidXmlPattern = Pattern - .compile("([^\\t\\n\\r\\u0020-\\ud7ff\\ue000-\\ufffd\\u10000-\\u10ffff]+|[&<>])"); - - // Patter to extract the converter name if any - private static final Pattern converterPattern = Pattern.compile(".*\\((.*)\\)"); - - private static final String[] oaidcElement = new String[] { "title", - "creator", "subject", "description", "publisher", "contributor", - "date", "type", "format", "identifier", "source", "language", - "relation", "coverage", "rights" }; - - /** Location of config file */ - private static final String configFilePath = ConfigurationManager - .getProperty("dspace.dir") - + File.separator - + "config" - + File.separator - + "crosswalks" - + File.separator + "oaidc.properties"; - - /** log4j logger */ - private static Logger log = Logger.getLogger(OAIDCCrosswalk.class); - - private static final Map> config = new HashMap>(); - - static - { - // Read in configuration - Properties crosswalkProps = new Properties(); - FileInputStream fis = null; - try - { - fis = new FileInputStream(configFilePath); - crosswalkProps.load(fis); - } - catch (IOException e) - { - throw new IllegalArgumentException( - "Wrong configuration for OAI_DC", e); - } - finally - { - if (fis != null) - { - try - { - fis.close(); - } - catch (IOException ioe) - { - log.error(ioe); - } - } - } - - Set keySet = crosswalkProps.keySet(); - if (keySet != null) - { - for (Object key : keySet) - { - String oaielement = crosswalkProps.getProperty((String) key); - if (oaielement != null && !oaielement.trim().equals("")) - { - Set tmp = config.get(oaielement); - if (tmp == null) - { - tmp = new HashSet(); - } - - tmp.add((String) key); - config.put(oaielement, tmp); - } - } - } - else - { - throw new IllegalArgumentException( - "Configurazione errata per l'uscita OAI_DC"); - } - } - - public OAIDCCrosswalk(Properties properties) - { - super("http://www.openarchives.org/OAI/2.0/oai_dc/ " - + "http://www.openarchives.org/OAI/2.0/oai_dc.xsd"); - } - - public boolean isAvailableFor(Object nativeItem) - { - // We have DC for everything - return true; - } - - public String createMetadata(Object nativeItem) - throws CannotDisseminateFormatException - { - Item item = ((HarvestedItemInfo) nativeItem).item; - - StringBuffer metadata = new StringBuffer(); - - metadata - .append( - ""); - - for (String element : oaidcElement) - { - Set itemMetadata = config.get(element); - - if (itemMetadata != null && itemMetadata.size() > 0) - { - for (String mdString : itemMetadata) - { - String converterName = null; - IConverter converter = null; - Matcher converterMatcher = converterPattern.matcher(mdString); - if (converterMatcher.matches()) - { - converterName = converterMatcher.group(1); - converter = (IConverter) PluginManager.getNamedPlugin( - IConverter.class, converterName); - if (converter == null) - { - log.warn(LogManager.getHeader(null, - "createMetadata", - "no converter plugin found with name " - + converterName + " for metadata " - + mdString)); - } - } - - DCValue[] dcValues; - if (converterName != null) - { - dcValues = item.getMetadata(mdString.replaceAll("\\(" - + converterName + "\\)", "")); - } - else - { - dcValues = item.getMetadata(mdString); - } - - try - { - for (DCValue dcValue : dcValues) - { - if (!MetadataExposure.isHidden(((HarvestedItemInfo) nativeItem).context, - dcValue.schema, dcValue.element, dcValue.qualifier)) - { - String value; - if (converter != null) - { - value = converter.makeConversion(dcValue.value); - } - else - { - value = dcValue.value; - } - - // Also replace all invalid characters with ' ' - if (value != null) - { - StringBuffer valueBuf = new StringBuffer(value - .length()); - Matcher xmlMatcher = invalidXmlPattern - .matcher(value.trim()); - while (xmlMatcher.find()) - { - String group = xmlMatcher.group(); - - // group will either contain a character that we - // need to encode for xml - // (ie. <, > or &), or it will be an invalid - // character - // test the contents and replace appropriately - - if (group.equals("&")) - { - xmlMatcher.appendReplacement(valueBuf, - "&"); - } - else if (group.equals("<")) - { - xmlMatcher.appendReplacement(valueBuf, - "<"); - } - else if (group.equals(">")) - { - xmlMatcher.appendReplacement(valueBuf, - ">"); - } - else - { - xmlMatcher.appendReplacement(valueBuf, " "); - } - } - - // add bit of the string after the final match - xmlMatcher.appendTail(valueBuf); - - metadata.append("") - .append(valueBuf.toString()) - .append(""); - } - } - } - } - catch (SQLException e) - { - // Stack loss as exception does not support cause - throw new CannotDisseminateFormatException(e.toString()); - } - } - } - } - - metadata.append(""); - - return metadata.toString(); - } -} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/PluginCrosswalk.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/PluginCrosswalk.java deleted file mode 100644 index ca129c8602..0000000000 --- a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/PluginCrosswalk.java +++ /dev/null @@ -1,169 +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.oai; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.Properties; - -import org.apache.log4j.Logger; -import org.dspace.content.Item; -import org.dspace.content.crosswalk.DisseminationCrosswalk; -import org.dspace.core.PluginManager; -import org.dspace.search.HarvestedItemInfo; -import org.jdom.output.XMLOutputter; - -import ORG.oclc.oai.server.crosswalk.Crosswalk; -import ORG.oclc.oai.server.verb.CannotDisseminateFormatException; - -/** - * An OAICat Crosswalk implementation that calls, in turn, on - * DisseminationCrosswalk plugins. - * It is configured so its "OAI schema label" matches the name of a - * DisseminationCrosswalk plugin. This class - * will then recognize its name and invoke the correct crosswalk - * to produce the results it sends out. - *

- * Configuration: - * In the OAICat configuration file (e.g. oaicat.properties - * add a line like this for each plugin crosswalk you wish to provide: - *

- *   Crosswalks.Plugin-Name=org.dspace.app.oai.PluginCrosswalk
- *
- *    e.g.
- *
- *   Crosswalks.DC=org.dspace.app.oai.PluginCrosswalk
- * 
- * This creates an OAI metadata prefix "DC" which is implemented - * by the dissemination crosswalk plugin that answers to the name "DC". - * It, in turn, could be found in the DSpace configuration in a line like: - *
- *  plugin.named.org.dspace.content.crosswalk.DisseminationCrosswalk = \
- *    org.dspace.content.crosswalk.SimpleDCDisseminationCrosswalk = DC
- * 
- * - *

- * Note that all OAI crosswalks are instances of this same class, since - * the instance gets bound to a specific DisseminationCrosswalk - * when it is created. - *

- * WARNING: This requires at the OAICAT java library version 1.5.38. - * It does NOT work with some older versions. - * - * @author Larry Stone - * @version $Revision$ - */ -public class PluginCrosswalk extends Crosswalk -{ - /** log4j category */ - private static Logger log = Logger.getLogger(PluginCrosswalk.class); - - private DisseminationCrosswalk xwalk = null; - - // preserve the label from config property for diagnostics. - private String schemaLabel = null; - - private static XMLOutputter outputUgly = new XMLOutputter(); - - /** - * Prepare a "schema location" string for the oaicat Crosswalk - * class's initialization. This is a string consisting of the - * namespace URI, a space, and the schema URL, for the XML - * element to be included in the OAI report. This is not documented - * in oaicat's manuals so we mention it here. - * - * Since this gets called by the constructor, we can't initialize the - * xwalk field so the plugin gets thrown away. - */ - private static String makeSchemaLocation(String schemaLabel) - { - DisseminationCrosswalk xwalk = (DisseminationCrosswalk) - PluginManager.getNamedPlugin(DisseminationCrosswalk.class, - schemaLabel); - if (xwalk != null) - { - String schemaLoc = xwalk.getSchemaLocation(); - - // initialize the oaicat Crosswalk with a "schemalocation" string, - // which is "{namespace-URI} {schema-URL}" (space separated) - if (schemaLoc != null) - { - log.debug("Initialized schemaLabel="+schemaLabel+" with schemaLocation = \""+schemaLoc+"\""); - return schemaLoc; - } - log.error("makeSchemaLocation: crosswalk cannot provide schemaLocation, label="+schemaLabel); - return "Error No-schemaLocation-for-"+schemaLabel; - } - log.error("No crosswalk found, makeSchemaLocation giving up, label="+schemaLabel); - return "Error No-crosswalk-for-"+schemaLabel; - } - - /** - * Constructor; called by - * ORG.oclc.oai.server.crosswalk.Crosswalks, which tries first with - * args (String schemaLabel, Properties properties). This is - * convenient since it lets us use that label to initialize this - * instance of the plugin with the DisseminationCrosswalk crosswalk - * corresponding to that schemaLabel, instead of creating a subclass - * for each one. - *

- * WARNING: This requires at the OAICAT java library version 1.5.37. - * It does NOT work with some older versions. - */ - public PluginCrosswalk(String schemaLabel, Properties properties) - { - super(makeSchemaLocation(schemaLabel)); - xwalk = (DisseminationCrosswalk)PluginManager.getNamedPlugin( - DisseminationCrosswalk.class, schemaLabel); - this.schemaLabel = schemaLabel; - } - - /** - * @return true if this dissemination is available for the item. - */ - public boolean isAvailableFor(Object nativeItem) - { - Item item = ((HarvestedItemInfo) nativeItem).item; - return xwalk.canDisseminate(item); - } - - /** - * Do the crosswalk. Returns serialized XML in a string. - */ - public String createMetadata(Object nativeItem) - throws CannotDisseminateFormatException - { - Item item = ((HarvestedItemInfo) nativeItem).item; - try - { - log.debug("OAI plugin, schema="+schemaLabel+", preferList="+String.valueOf(xwalk.preferList())); - if (xwalk.preferList()) - { - return outputUgly.outputString(xwalk.disseminateList(item)); - } - else - { - return outputUgly.outputString(xwalk.disseminateElement(item)); - } - } - catch (Exception e) - { - log.error(this.getClass().getName()+ - ": hiding exception in CannotDisseminateFormatException:"+ - e.toString()); - - StringWriter sw = new StringWriter(); - e.printStackTrace(new PrintWriter(sw)); - log.error("*** Stack trace follows:"); - log.error(sw.toString()); - - // Stack loss as exception does not support cause - throw new CannotDisseminateFormatException(schemaLabel); - } - } -} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/RDFCrosswalk.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/RDFCrosswalk.java deleted file mode 100644 index 1bc4b3a9c6..0000000000 --- a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/RDFCrosswalk.java +++ /dev/null @@ -1,245 +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.oai; - -import java.util.Properties; -import java.sql.SQLException; - -import org.dspace.app.util.Util; -import org.dspace.content.DCValue; -import org.dspace.content.Item; -import org.dspace.content.Bitstream; -import org.dspace.content.Bundle; -import org.dspace.content.Collection; -import org.dspace.content.Community; -import org.dspace.core.Constants; -import org.dspace.core.ConfigurationManager; -import org.dspace.search.HarvestedItemInfo; - -import ORG.oclc.oai.server.crosswalk.Crosswalk; -import ORG.oclc.oai.server.verb.CannotDisseminateFormatException; - -/** - * An OAICat Crosswalk implementation that extracts - * DSpace items into typed RDF format. - * - * @author Richard Rodgers - * @version $Revision$ - */ -public class RDFCrosswalk extends Crosswalk -{ - // base URL for thumbnails - private String baseUrl = null; - // hostname for rdf URI - private String hostName = null; - - public RDFCrosswalk(Properties properties) - { - super( - "http://www.openarchives.org/OAI/2.0/rdf/ http://www.openarchives.org/OAI/2.0/rdf.xsd"); - baseUrl = ConfigurationManager.getProperty("dspace.url"); - hostName = ConfigurationManager.getProperty("dspace.hostname"); - } - - public boolean isAvailableFor(Object nativeItem) - { - // Only implemented for items so far - return (nativeItem instanceof HarvestedItemInfo); - } - - public String createMetadata(Object nativeItem) - throws CannotDisseminateFormatException - { - HarvestedItemInfo itemInfo = (HarvestedItemInfo)nativeItem; - Item item = itemInfo.item; - - // Get all the DC - DCValue[] allDC = item.getDC(Item.ANY, Item.ANY, Item.ANY); - - StringBuffer metadata = new StringBuffer(); - - /* - metadata - .append( - ""); - */ - - metadata - .append( - ""); - - - // construct URI for item - metadata.append(""); - - for (int i = 0; i < allDC.length; i++) - { - if (screened(allDC[i])) - { - String element = allDC[i].element; - - // contributor.author exposed as 'creator' - if (allDC[i].element.equals("contributor") - && (allDC[i].qualifier != null) - && allDC[i].qualifier.equals("author")) - { - element = "creator"; - } - - // Escape XML chars <, > and & - String value = allDC[i].value; - - // Check for null values - if (value == null) - { - value = ""; - } - - // First do &'s - need to be careful not to replace the - // & in "&" again! - int c = -1; - - while ((c = value.indexOf("&", c + 1)) > -1) - { - value = value.substring(0, c) + "&" - + value.substring(c + 1); - } - - while ((c = value.indexOf("<")) > -1) - { - value = value.substring(0, c) + "<" - + value.substring(c + 1); - } - - while ((c = value.indexOf(">")) > -1) - { - value = value.substring(0, c) + ">" - + value.substring(c + 1); - } - - metadata.append("") - .append(value) - .append(""); - } - } - - // add extended info - collection, communities, and thumbnail URLs - Collection[] colls = null; - Community[] comms = null; - Bundle[] origBundles = null; - Bundle[] thumbBundles = null; - try - { - colls = item.getCollections(); - comms = item.getCommunities(); - origBundles = item.getBundles("ORIGINAL"); - thumbBundles = item.getBundles("THUMBNAIL"); - } - catch(SQLException sqlE) - { - } - - // all parent communities map to DC source - for (int i = 0; i < comms.length; i++) - { - metadata.append("") - .append(comms[i].getMetadata("name")) - .append(""); - } - // as do collections - for (int j = 0; j < colls.length; j++) - { - metadata.append("") - .append(colls[j].getMetadata("name")) - .append(""); - } - - if (origBundles.length > 0) - { - Bitstream[] bitstreams = origBundles[0].getBitstreams(); - // add a URL for each original that has a thumbnail - for (int j = 0; j < bitstreams.length; j++) - { - String tName = bitstreams[j].getName() + ".jpg"; - Bitstream tb = null; - - if (thumbBundles.length > 0) - { - tb = thumbBundles[0].getBitstreamByName(tName); - } - - if (tb != null) - { - String thumbUrl = null; - try - { - thumbUrl = baseUrl + "/retrieve/" + tb.getID() + "/" + - Util.encodeBitstreamName(tb.getName(), - Constants.DEFAULT_ENCODING); - } - catch(Exception e) - { - } - metadata.append("") - .append(thumbUrl) - .append(""); - } - } - } - //metadata.append(""); - metadata.append(""); - metadata.append(""); - - return metadata.toString(); - } - - /* - * Exclude Item DC elements unsuitable for harvest - */ - private boolean screened(DCValue dcValue) - { - // description.providence - if (isQualified(dcValue, "description", "provenance")) - { - return false; - } - // format.extent - if (isQualified(dcValue, "format", "extent")) - { - return false; - } - // date.available is algorithmically identical to date.accessioned - // suppress one - if (isQualified(dcValue, "date", "accessioned")) - { - return false; - } - return true; - } - - private boolean isQualified(DCValue dcValue, String elName, String qualName) - { - return (dcValue.element.equals(elName) && - dcValue.qualifier != null && - dcValue.qualifier.equals(qualName)); - } -} \ No newline at end of file diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/UKETDDCCrosswalk.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/UKETDDCCrosswalk.java deleted file mode 100644 index baa115b71e..0000000000 --- a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/app/oai/UKETDDCCrosswalk.java +++ /dev/null @@ -1,701 +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.oai; - -import java.sql.SQLException; -import java.util.Properties; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.dspace.core.ConfigurationManager; -import org.dspace.core.Utils; -import org.dspace.search.HarvestedItemInfo; -import org.dspace.content.*; - -import ORG.oclc.oai.server.crosswalk.Crosswalk; -import ORG.oclc.oai.server.verb.CannotDisseminateFormatException; - -/** - * A Crosswalk implementation that extracts qualified Dublin Core from - * DSpace items into the uketd_dc format. - * - * It supports the writing of UKETD_DC metadata - * in a METS document and to make the schema URIs available for - * inclusion in such a METS document. For this reason, the writing - * of the metadata itself has been separated from the writing - * of the schemas. - * This version places the writing of the header and metadata - * in its own method called by createMetadata so the headers are - * included in the UKETD_METS that also uses those methods. - * This allows the writeMetadata method to remain unchanged, - * with no header information included. It is therefore consistent with - * other DSpace crosswalks. - * - * @author Paul Needham (Cranfield University) - * @author Jon Bell & Stuart Lewis (Aberystwyth University) - */ -public class UKETDDCCrosswalk extends Crosswalk -{ - // Pattern containing all the characters we want to filter out / replace - // converting a String to xml - private static final Pattern invalidXmlPattern = - Pattern.compile("([^\\t\\n\\r\\u0020-\\ud7ff\\ue000-\\ufffd\\u10000-\\u10ffff]+|[&<>])"); - - // String constants for metadata schemas... - - /** Used to open the metadata in a OAI-PMH record. */ - private String uketdIn = "\n"); - metadata.append (writeMetadata (item)); - metadata.append ("\n"); - return metadata.toString ( ); - } - - - /** - * Writes the UKETD_DC metadata for the specified item. - * It simply gets hold of the Dublin Core for an Item - * and converts it to UKEDT_DC, including the splitting - * of the Dublin Core publisher and type fields. - * The metadata is identical to that returned by - * the original version's create metadata method, - * without the schema information. - * This method does no checking of the correctness of the - * metadata format, nor does it throw any exception. - * - * @param item a org.dspace.content.Item - * @return a String, the item's metadata in UKETD_DC xml. - */ - public String writeMetadata(Item item) - { - // The string we are constructing - StringBuffer metadata = new StringBuffer(); - - // Get all the DC - DCValue[] allDC = item.getMetadata(MetadataSchema.DC_SCHEMA, Item.ANY, Item.ANY, Item.ANY); - - // Get the handle of the item - String itemhandle = item.getHandle(); - - for (int i = 0; i < allDC.length; i++) - { - // Get the element, qualifier and value - String element = allDC[i].element; - String qualifier = allDC[i].qualifier; - String value = Utils.addEntities(allDC[i].value); - - // title - if (allDC[i].element.equals("title")) - { - if (allDC[i].qualifier != null) { - if (allDC[i].qualifier.equals("alternative")) - { - // title.alternative exposed as 'dcterms:alternative' - this.makeDCTermsElement(qualifier, null, value, metadata); - } - } else - { - this.makeDCElement(element, null, value, metadata); - } - } - - // contributor - if (allDC[i].element.equals("contributor")) - { - if (allDC[i].qualifier != null) { - if (allDC[i].qualifier.equals("author")) - { - this.makeDCElement("creator", null, value, metadata); - } else if ((allDC[i].qualifier.equals("advisor")) || - (allDC[i].qualifier.equals("sponsor"))) - { - // contributor.qualifier exposed as 'uketdterms:qualifier' - this.makeUKDCTermsElement(qualifier, null, value, metadata); - } else if (allDC[i].qualifier.equals("funder")) - { - // contributor.qualifier exposed as 'uketdterms:qualifier' - this.makeUKDCTermsElement("sponsor", null, value, metadata); - } else - { - // contributor.qualifier exposed as 'dcterms:qualifier' - this.makeDCTermsElement(qualifier, null, value, metadata); - } - } else { - this.makeDCElement(element, null, value, metadata); - } - } - - // subject - if (allDC[i].element.equals("subject")) - { - if (allDC[i].qualifier != null) { - boolean ddc = allDC[i].qualifier.equals("ddc"); - boolean lcc = allDC[i].qualifier.equals("lcc"); - boolean lcsh = allDC[i].qualifier.equals("lcsh"); - boolean mesh = allDC[i].qualifier.equals("mesh"); - boolean udc = allDC[i].qualifier.equals("udc"); - if (ddc || lcc || lcsh || mesh || udc) - { - // subject.qualifier exposed as 'dc:element xsi:type="dcterms:qualifier"' - qualifier = qualifier.toUpperCase(); - this.makeDCElement(element, qualifier, value, metadata); - } else - { - this.makeDCElement(element, null, value, metadata); - } - } else - { - this.makeDCElement(element, null, value, metadata); - } - } - - // description - if (allDC[i].element.equals("description")) - { - if (allDC[i].qualifier != null) - { - if (allDC[i].qualifier.equals("abstract")) - { - // e.g. description.abstract exposed as 'dcterms:abstract' - this.makeDCTermsElement(qualifier, null, value, metadata); - } else if (allDC[i].qualifier.equals("sponsorship")) - { - // description.sponsorship exposed as 'uketdterms:sponsor"' - this.makeUKDCTermsElement("sponsor", null, value, metadata); - } - } else { - this.makeDCElement(element, null, value, metadata); - } - } - - // publisher - if (allDC[i].element.equals("publisher")) - { - if (allDC[i].qualifier != null) { - if ((allDC[i].qualifier.equals("department")) || - (allDC[i].qualifier.equals("commercial"))) - { - this.makeUKDCTermsElement(qualifier, null, value, metadata); - } - } else { - String[] pubParts = value.split("(? 1) && (pubParts[1] != null)) { - dept.append(pubParts[1] + ";"); - } - if ((pubParts.length > 2) && (pubParts[2] != null)) { - dept.append(" " + pubParts[2]); - } - if (dept.length() > 0) { - this.makeUKDCTermsElement("department", null, - dept.toString(), metadata); - } - } - - } - - // date - if (allDC[i].element.equals("date")) - { - if (allDC[i].qualifier != null) - { - if (allDC[i].qualifier.equals("issued")) - { - this.makeDCTermsElement(qualifier, null, value, metadata); - } else - { - this.makeDCElement(element, null, value, metadata); - } - } else - { - this.makeDCElement(element, null, value, metadata); - } - } - - // type - if (allDC[i].element.equals("type")) - { - if (allDC[i].qualifier != null) - { - if ((allDC[i].qualifier.equals("qualificationlevel")) || - (allDC[i].qualifier.equals("qualificationname"))) - { - this.makeUKDCTermsElement(qualifier, null, value, metadata); - } - } else { - String[] Typepart = value.split("[;]"); - this.makeDCElement(element, null, Typepart[0], metadata); - if ((Typepart.length > 1) && (Typepart[1] != null)) - { - this.makeUKDCTermsElement("qualificationlevel", null, - Typepart[1], metadata); - } if ((Typepart.length > 2) && (Typepart[2] != null)) - { - this.makeUKDCTermsElement("qualificationname", null, - Typepart[2], metadata); - } - } - } - - // language - if (allDC[i].element.equals("language")) - { - if (allDC[i].qualifier != null) { - if (allDC[i].qualifier.equals("iso")) - { - // language.iso exposed as 'dc:element xsi:type="dcterms:qualifier"' - this.makeDCElement(element, "ISO639-2", value, metadata); - } else - { - this.makeDCElement(element, null, value, metadata); - } - } else - { - this.makeDCElement(element, null, value, metadata); - } - } - - // relation - if (allDC[i].element.equals("relation")) - { - if (allDC[i].qualifier != null) { - if (allDC[i].qualifier.equals("hasversion")) - { - // relation.hasversion exposed as 'dcterms:qualifier' - this.makeDCElement("hasVersion", null, value, metadata); - } else if ((allDC[i].qualifier.equals("references")) || - (allDC[i].qualifier.equals("requires"))) - { - // relation.references exposed as 'dcterms:qualifier' - this.makeDCTermsElement(qualifier, null, value, metadata); - } else - { - this.makeDCElement(element, null, value, metadata); - } - } else - { - this.makeDCElement(element, null, value, metadata); - } - } - - // format - if (allDC[i].element.equals("format")) - { - if (allDC[i].qualifier != null) - { - if (allDC[i].qualifier.equals("extent")) - { - // format exposed as 'dcterms:qualifier' - this.makeDCTermsElement(qualifier, null, value, metadata); - } else if (allDC[i].qualifier.equals("mimetype")) - { - this.makeDCElement(element, "IMT", value, metadata); - } - } else - { - // format exposed as 'dc:element' - this.makeDCElement(element, null, value, metadata); - } - } - - // identifier - if (allDC[i].element.equals("identifier")) - { - if (allDC[i].qualifier != null) - { - if (allDC[i].qualifier.equals("uri")) - { - this.makeDCTermsElement("isReferencedBy", "URI", value, metadata); - } else if (allDC[i].qualifier.equals("citation")) - { - this.makeDCTermsElement("hasVersion", null, value, metadata); - } else if (allDC[i].qualifier.equals("grantnumber")) - { - this.makeUKDCTermsElement(qualifier, null, value, metadata); - } - } else - { - // identifier exposed as 'dc:element' - this.makeDCElement(element, null, value, metadata); - } - } - - // rights - if (allDC[i].element.equals("rights")) - { - if (allDC[i].qualifier != null) - { - if ((allDC[i].qualifier.equals("embargodate")) || - (allDC[i].qualifier.equals("embargoreason"))) - { - this.makeUKDCTermsElement(qualifier, null, value, metadata); - } else - { - // rights exposed as 'dc:element' - this.makeDCElement(element, null, value, metadata); - } - } else - { - // rights exposed as 'dc:element' - this.makeDCElement(element, null, value, metadata); - } - } - } - - // Generate bitstream URIs - Bundle[] bundles = {}; - try - { - bundles = item.getBundles("ORIGINAL"); - String url; - if (bundles.length > 0) - { - // Itterate through each bundle - for (int i = 0; i < bundles.length; i++) - { - // Itterate through each bitstream - Bitstream[] bitstreams = bundles[i].getBitstreams(); - for (int k = 0; k < bitstreams.length ; k++) - { - // Skip internal types - if (!bitstreams[k].getFormat().isInternal()) - { - url = ConfigurationManager.getProperty("dspace.url") + - "/bitstream/" + itemhandle + "/" + - bitstreams[k].getSequenceID() + "/" + - bitstreams[k].getName(); - this.makeDCElement("identifier", "URI", url, metadata); - this.makeUKDCTermsElement("checksum", - bitstreams[k].getChecksumAlgorithm(), - bitstreams[k].getChecksum(), metadata); - } - } - } - } - } catch (SQLException sqle) - { - // Nothing we can do - } - - // Return the metadata - all done! - return metadata.toString(); - } - - /** - * Private wrapper method to create a DC term element. - * - * @param element The element name - * @param qualifier The qualifier name (or null) - * @param value The value of the element - * @param buffer The buffer to add the element to - * @return The buffer with the new element appended to - */ - private StringBuffer makeDCElement(String element, String qualifier, - String value, StringBuffer buffer) - { - return this.makeTermsElement(element, qualifier, value, - buffer, "dc", "dcterms"); - } - - /** - * Private wrapper method to create a DCterms term element. - * - * @param element The element name - * @param qualifier The qualifier name (or null) - * @param value The value of the element - * @param buffer The buffer to add the element to - * @return The buffer with the new element appended to - */ - private StringBuffer makeDCTermsElement(String element, String qualifier, - String value, StringBuffer buffer) - { - return this.makeTermsElement(element, qualifier, value, - buffer, "dcterms", "dcterms"); - } - - /** - * Private wrapper method to create a UKETD DC term element. - * - * @param element The element name - * @param qualifier The qualifier name (or null) - * @param value The value of the element - * @param buffer The buffer to add the element to - * @return The buffer with the new element appended to - */ - private StringBuffer makeUKDCTermsElement(String element, String qualifier, - String value, StringBuffer buffer) - { - return this.makeTermsElement(element, qualifier, value, - buffer, "uketdterms", "uketdterms"); - } - - /** - * Private wrapper method to create an element. - * - * @param element The element name - * @param qualifier The qualifier name (or null) - * @param value The value of the element - * @param buffer The buffer to add the element to - * @param terms The namespace of the term - * @return The buffer with the new element appended to - */ - - private StringBuffer makeTermsElement(String element, String qualifier, - String value, StringBuffer buffer, - String namespace, String terms) - { - // Escape XML chars <, > and & - // Also replace all invalid characters with ' ' - if (value != null) - { - StringBuffer valueBuf = new StringBuffer(value.length()); - Matcher xmlMatcher = invalidXmlPattern.matcher(value.trim()); - while (xmlMatcher.find()) - { - String group = xmlMatcher.group(); - - // group will either contain a character that we need to encode for xml - // (ie. <, > or &), or it will be an invalid character - // test the contents and replace appropriately - if ("&".equals(group)) - { - xmlMatcher.appendReplacement(valueBuf, "&"); - } - else if ("<".equals(group)) - { - xmlMatcher.appendReplacement(valueBuf, "<"); - } - else if (">".equals(group)) - { - xmlMatcher.appendReplacement(valueBuf, ">"); - } - else - { - xmlMatcher.appendReplacement(valueBuf, " "); - } - } - - // add bit of the string after the final match - xmlMatcher.appendTail(valueBuf); - - if (qualifier == null) - { - buffer.append("<").append(namespace).append(":").append(element).append(">").append(valueBuf.toString()).append("\n"); - } else - { - buffer.append("<").append(namespace).append(":").append(element).append(" xsi:type=\"").append(terms).append(":").append(qualifier).append("\">").append(valueBuf.toString()).append("\n"); - } - } - else - { - buffer.append("<").append(namespace).append(":").append(element).append(" />\n"); - } - - // Return the updated buffer - return buffer; - } -} \ No newline at end of file diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/DSpaceOAIDataProvider.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/DSpaceOAIDataProvider.java new file mode 100644 index 0000000000..25cbc6b4b7 --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/DSpaceOAIDataProvider.java @@ -0,0 +1,173 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.xoai; + +import java.io.IOException; +import java.io.OutputStream; +import java.sql.SQLException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.apache.solr.client.solrj.SolrServerException; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Context; +import org.dspace.xoai.data.DSpaceIdentify; +import org.dspace.xoai.data.DSpaceItemDatabaseRepository; +import org.dspace.xoai.data.DSpaceItemRepository; +import org.dspace.xoai.data.DSpaceItemSolrRepository; +import org.dspace.xoai.data.DSpaceSetRepository; +import org.dspace.xoai.filter.DSpaceFilter; +import org.dspace.xoai.solr.DSpaceSolrServer; +import org.dspace.xoai.util.XOAICacheManager; + +import com.lyncode.xoai.dataprovider.OAIDataProvider; +import com.lyncode.xoai.dataprovider.OAIRequestParameters; +import com.lyncode.xoai.dataprovider.core.XOAIManager; +import com.lyncode.xoai.dataprovider.exceptions.InvalidContextException; +import com.lyncode.xoai.dataprovider.filter.AbstractFilter; + +/** + * + * @author Lyncode Development Team + */ +@SuppressWarnings("serial") +public class DSpaceOAIDataProvider extends HttpServlet +{ + private static Logger log = LogManager + .getLogger(DSpaceOAIDataProvider.class); + + @Override + public void init() + { + try + { + XOAIManager.initialize(ConfigurationManager + .getProperty("oai", "config.dir")); + if (!"database".equals(ConfigurationManager.getProperty("oai", "storage"))) { + DSpaceSolrServer.getServer(); + } + System.out.println("[OAI 2.0] Initialized"); + } + catch (com.lyncode.xoai.dataprovider.exceptions.ConfigurationException e) + { + System.out.println("Unable to configure XOAI (OAI 2.0 Core)"); + e.printStackTrace(); + } + catch (SolrServerException e) + { + System.out.println("Unable to configure XOAI (OAI 2.0 Core)"); + e.printStackTrace(); + } + } + + public void destroy() + { + System.out.println("[OAI 2.0] Destroyed"); + } + + @Override + protected void doGet(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException + { + request.setCharacterEncoding("UTF-8"); + Context context = null; + + try + { + log.debug("OAI 2.0 request received"); + context = new Context(); + + // Filters require database connection -> dependency injection? + for (AbstractFilter filter : XOAIManager.getManager() + .getFilterManager().getFilters()) + if (filter instanceof DSpaceFilter) + ((DSpaceFilter) filter).initialize(context); + + DSpaceItemRepository repository; + String storage = ConfigurationManager + .getProperty("oai", "storage"); + if (storage == null + || !storage.trim().toLowerCase().equals("database")) + { + log.debug("Using Solr for querying"); + repository = new DSpaceItemSolrRepository(); + } + else + { + log.debug("Using Database for querying"); + repository = new DSpaceItemDatabaseRepository(context); + } + + log.debug("Creating OAI Data Provider Instance"); + OAIDataProvider dataProvider = new OAIDataProvider(request + .getPathInfo().replace("/", ""), new DSpaceIdentify( + context, request), new DSpaceSetRepository(context), + repository); + + log.debug("Reading parameters from request"); + + OutputStream out = response.getOutputStream(); + OAIRequestParameters parameters = new OAIRequestParameters(); + parameters.setFrom(request.getParameter("from")); + parameters.setUntil(request.getParameter("until")); + parameters.setSet(request.getParameter("set")); + parameters.setVerb(request.getParameter("verb")); + parameters + .setMetadataPrefix(request.getParameter("metadataPrefix")); + parameters.setIdentifier(request.getParameter("identifier")); + parameters.setResumptionToken(request + .getParameter("resumptionToken")); + + response.setContentType("application/xml"); + + String identification = request.getPathInfo().replace("/", "") + + parameters.getVerb() + parameters.getMetadataPrefix() + + parameters.getIdentifier() + + parameters.getResumptionToken() + parameters.getSet() + + parameters.getFrom() + parameters.getUntil(); + + log.debug("Handling OAI request"); + XOAICacheManager.handle(identification, dataProvider, parameters, out); + + out.flush(); + out.close(); + + if (context != null) + context.abort(); + } + catch (SQLException e) + { + log.error(e.getMessage(), e); + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + catch (InvalidContextException e) + { + log.error(e.getMessage(), e); + if (context != null) + context.abort(); + response.sendError(HttpServletResponse.SC_NOT_FOUND, + "Requested OAI context \"" + + request.getPathInfo().replace("/", "") + + "\" does not exist"); + } + + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException + { + this.doGet(req, resp); + } + +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/app/XOAI.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/app/XOAI.java new file mode 100644 index 0000000000..844c3bd087 --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/app/XOAI.java @@ -0,0 +1,527 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.xoai.app; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.ConnectException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +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.log4j.LogManager; +import org.apache.log4j.Logger; +import org.apache.solr.client.solrj.SolrQuery; +import org.apache.solr.client.solrj.SolrQuery.ORDER; +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.AuthorizeException; +import org.dspace.authorize.AuthorizeManager; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DCValue; +import org.dspace.content.Item; +import org.dspace.content.ItemIterator; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.storage.rdbms.DatabaseManager; +import org.dspace.storage.rdbms.TableRowIterator; +import org.dspace.xoai.data.DSpaceDatabaseItem; +import org.dspace.xoai.exceptions.CompilingException; +import org.dspace.xoai.solr.DSpaceSolrSearch; +import org.dspace.xoai.solr.DSpaceSolrServer; +import org.dspace.xoai.solr.exceptions.DSpaceSolrException; +import org.dspace.xoai.solr.exceptions.DSpaceSolrIndexerException; +import org.dspace.xoai.util.ItemUtils; +import org.dspace.xoai.util.XOAICacheManager; +import org.dspace.xoai.util.XOAIDatabaseManager; + +import com.lyncode.xoai.dataprovider.exceptions.MetadataBindException; +import com.lyncode.xoai.dataprovider.util.MarshallingUtils; + +/** + * + * @author Lyncode Development Team + */ +@SuppressWarnings("deprecation") +public class XOAI +{ + private static Logger log = LogManager.getLogger(XOAI.class); + + private Context _context; + + private boolean _optimize; + + private boolean _verbose; + + private boolean _clean; + + private static List getFileFormats(Item item) + { + List formats = new ArrayList(); + try + { + for (Bundle b : item.getBundles("ORIGINAL")) + { + for (Bitstream bs : b.getBitstreams()) + { + if (!formats.contains(bs.getFormat().getMIMEType())) + { + formats.add(bs.getFormat().getMIMEType()); + } + } + } + } + catch (SQLException ex) + { + log.error(ex.getMessage(), ex); + } + return formats; + } + + public XOAI(Context context, boolean optimize, boolean clean, boolean verbose) + { + _context = context; + _optimize = optimize; + _clean = clean; + _verbose = verbose; + } + + public XOAI(Context ctx, boolean hasOption) + { + _context = ctx; + _verbose = hasOption; + } + + private void println(String line) + { + System.out.println(line); + } + + public int index() throws DSpaceSolrIndexerException + { + int result = 0; + try + { + + if (_clean) { + clearIndex(); + System.out.println("Using full import."); + this.indexAll(); + } else { + SolrQuery solrParams = new SolrQuery("*:*") + .addField("item.lastmodified") + .addSortField("item.lastmodified", ORDER.desc).setRows(1); + + SolrDocumentList results = DSpaceSolrSearch.query(solrParams); + if (results.getNumFound() == 0) + { + System.out.println("There are no indexed documents, using full import."); + result = this.indexAll(); + } + else + result = this.index((Date) results.get(0).getFieldValue("item.lastmodified")); + + } + DSpaceSolrServer.getServer().commit(); + + + if (_optimize) + { + println("Optimizing Index"); + DSpaceSolrServer.getServer().optimize(); + println("Index optimized"); + } + + // Set last compilation date + XOAICacheManager.setLastCompilationDate(new Date()); + return result; + } + catch (DSpaceSolrException ex) + { + throw new DSpaceSolrIndexerException(ex.getMessage(), ex); + } + catch (SolrServerException ex) + { + throw new DSpaceSolrIndexerException(ex.getMessage(), ex); + } + catch (IOException ex) + { + throw new DSpaceSolrIndexerException(ex.getMessage(), ex); + } + } + + private int index(Date last) throws DSpaceSolrIndexerException + { + System.out + .println("Incremental import. Searching for documents modified after: " + + last.toString()); + try + { + TableRowIterator iterator = DatabaseManager + .query(_context, + "SELECT item_id FROM item WHERE in_archive=TRUE AND last_modified > ?", + new java.sql.Timestamp(last.getTime())); + return this.index(iterator); + } + catch (SQLException ex) + { + throw new DSpaceSolrIndexerException(ex.getMessage(), ex); + } + } + + private int indexAll() throws DSpaceSolrIndexerException + { + System.out.println("Full import"); + try + { + TableRowIterator iterator = DatabaseManager.query(_context, + "SELECT item_id FROM item WHERE in_archive=TRUE"); + return this.index(iterator); + } + catch (SQLException ex) + { + throw new DSpaceSolrIndexerException(ex.getMessage(), ex); + } + } + + private int index(TableRowIterator iterator) + throws DSpaceSolrIndexerException + { + try + { + int i = 0; + SolrServer server = DSpaceSolrServer.getServer(); + while (iterator.hasNext()) + { + try + { + server.add(this.index(Item.find(_context, iterator.next() + .getIntColumn("item_id")))); + + _context.clearCache(); + } + catch (SQLException ex) + { + log.error(ex.getMessage(), ex); + } + catch (MetadataBindException e) + { + log.error(e.getMessage(), e); + } + i++; + if (i % 100 == 0) System.out.println(i+" items imported so far..."); + } + System.out.println("Total: "+i+" items"); + server.commit(); + return i; + } + catch (SQLException ex) + { + throw new DSpaceSolrIndexerException(ex.getMessage(), ex); + } + catch (SolrServerException ex) + { + throw new DSpaceSolrIndexerException(ex.getMessage(), ex); + } + catch (IOException ex) + { + throw new DSpaceSolrIndexerException(ex.getMessage(), ex); + } + } + + private SolrInputDocument index(Item item) throws SQLException, MetadataBindException + { + 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()); + 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 : XOAIDatabaseManager.flatParentCommunities(item)) + doc.addField("item.communities", + "com_" + com.getHandle().replace("/", "_")); + + DCValue[] allData = item.getMetadata(Item.ANY, Item.ANY, Item.ANY, + Item.ANY); + for (DCValue dc : allData) + { + String key = "metadata." + dc.schema + "." + dc.element; + if (dc.qualifier != null) + { + key += "." + dc.qualifier; + } + doc.addField(key, dc.value); + if (dc.authority != null) { + doc.addField(key + ".authority", dc.authority); + doc.addField(key + ".confidence", dc.confidence + ""); + } + } + + for (String f : getFileFormats(item)) + { + doc.addField("metadata.dc.format.mimetype", f); + } + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + MarshallingUtils.writeMetadata(out, ItemUtils.retrieveMetadata(item)); + doc.addField("item.compile", out.toString()); + + if (_verbose) + { + println("Item with handle "+handle+" indexed"); + } + + + return doc; + } + + private boolean isPublic(Item item) + { + try + { + AuthorizeManager.authorizeAction(_context, item, Constants.READ); + for (Bundle b : item.getBundles()) + AuthorizeManager.authorizeAction(_context, b, Constants.READ); + return true; + } + catch (AuthorizeException ex) + { + log.debug(ex.getMessage()); + } + catch (SQLException ex) + { + log.error(ex.getMessage()); + } + return false; + } + + + 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."); + return true; + } + + return false; + } + + private static boolean searchForReason(Throwable t) + { + if (getKnownExplanation(t)) + return true; + if (t.getCause() != null) + return searchForReason(t.getCause()); + return false; + } + + private static void clearIndex() throws DSpaceSolrIndexerException + { + try + { + System.out.println("Clearing index"); + DSpaceSolrServer.getServer().deleteByQuery("*:*"); + DSpaceSolrServer.getServer().commit(); + System.out.println("Index cleared"); + } + catch (SolrServerException ex) + { + throw new DSpaceSolrIndexerException(ex.getMessage(), ex); + } + catch (IOException ex) + { + throw new DSpaceSolrIndexerException(ex.getMessage(), ex); + } + } + + private static void cleanCache() + { + System.out.println("Purging cached OAI responses."); + XOAICacheManager.deleteCachedResponses(); + } + + private static final String COMMAND_IMPORT = "import"; + private static final String COMMAND_CLEAN_CACHE = "clean-cache"; + private static final String COMMAND_COMPILE_ITEMS = "compile-items"; + private static final String COMMAND_ERASE_COMPILED_ITEMS = "erase-compiled-items"; + + public static void main(String[] argv) + { + try + { + CommandLineParser parser = new PosixParser(); + Options options = new Options(); + options.addOption("c", "clear", false, "Clear index before indexing"); + options.addOption("o", "optimize", false, + "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"); + CommandLine line = parser.parse(options, argv); + + String[] validSolrCommands = { COMMAND_IMPORT, COMMAND_CLEAN_CACHE }; + String[] validDatabaseCommands = { COMMAND_CLEAN_CACHE, COMMAND_COMPILE_ITEMS, COMMAND_ERASE_COMPILED_ITEMS }; + + + boolean solr = true; // Assuming solr by default + solr = !("database").equals(ConfigurationManager.getProperty("oai", "storage")); + + + boolean run = false; + if (line.getArgs().length > 0) { + if (solr) { + if (Arrays.asList(validSolrCommands).contains(line.getArgs()[0])) { + run = true; + } + } else { + if (Arrays.asList(validDatabaseCommands).contains(line.getArgs()[0])) { + run = true; + } + } + } + + if (!line.hasOption('h') && run) { + System.out.println("OAI 2.0 manager action started"); + long start = System.currentTimeMillis(); + + String command = line.getArgs()[0]; + + if (COMMAND_IMPORT.equals(command)) { + Context ctx = new Context(); + XOAI indexer = new XOAI(ctx, + line.hasOption('o'), + line.hasOption('c'), + line.hasOption('v')); + + int imported = indexer.index(); + if (imported > 0) cleanCache(); + + ctx.abort(); + } else if (COMMAND_CLEAN_CACHE.equals(command)) { + cleanCache(); + } else if (COMMAND_COMPILE_ITEMS.equals(command)) { + + Context ctx = new Context(); + XOAI indexer = new XOAI(ctx, line.hasOption('v')); + + indexer.compile(); + + cleanCache(); + + ctx.abort(); + } else if (COMMAND_ERASE_COMPILED_ITEMS.equals(command)) { + cleanCompiledItems(); + cleanCache(); + } + + System.out.println("OAI 2.0 manager action ended. It took " + + ((System.currentTimeMillis() - start) / 1000) + + " seconds."); + } else { + usage(); + } + } + catch (Throwable ex) + { + if (!searchForReason(ex)) + { + ex.printStackTrace(); + } + log.error(ex.getMessage(), ex); + } + } + + private static void cleanCompiledItems() + { + System.out.println("Purging compiled items"); + XOAICacheManager.deleteCompiledItems(); + } + + private void compile() throws CompilingException + { + ItemIterator iterator; + try + { + Date last = XOAICacheManager.getLastCompilationDate(); + + if (last == null) { + System.out.println("Retrieving all items to be compiled"); + iterator = Item.findAll(_context); + } else { + System.out.println("Retrieving items modified after "+last+" to be compiled"); + String query = "SELECT * FROM item WHERE last_modified>?"; + iterator = new ItemIterator(_context, DatabaseManager.query(_context, query, new java.sql.Date(last.getTime()))); + } + + while (iterator.hasNext()) { + Item item = iterator.next(); + if (_verbose) System.out.println("Compiling item with handle: "+ item.getHandle()); + XOAICacheManager.compileItem(new DSpaceDatabaseItem(item)); + _context.clearCache(); + } + + XOAICacheManager.setLastCompilationDate(new Date()); + } + catch (SQLException e) + { + throw new CompilingException(e); + } + System.out.println("Items compiled"); + } + + private static void usage() + { + boolean solr = true; // Assuming solr by default + solr = !("database").equals(ConfigurationManager.getProperty("oai", "storage")); + + if (solr) { + System.out.println("OAI Manager Script"); + System.out.println("Syntax: oai [parameters]"); + System.out.println("> Possible actions:"); + System.out.println(" "+COMMAND_IMPORT+" - To import DSpace items into OAI index and cache system"); + System.out.println(" "+COMMAND_CLEAN_CACHE+" - Cleans the OAI cached responses"); + System.out.println("> Parameters:"); + System.out.println(" -o Optimize index after indexing ("+COMMAND_IMPORT+" only)"); + System.out.println(" -c Clear index ("+COMMAND_IMPORT+" only)"); + System.out.println(" -v Verbose output"); + System.out.println(" -h Shows this text"); + } else { + System.out.println("OAI Manager Script"); + System.out.println("Syntax: oai [parameters]"); + System.out.println("> Possible actions:"); + System.out.println(" "+COMMAND_CLEAN_CACHE+" - Cleans the OAI cached responses"); + System.out.println(" "+COMMAND_COMPILE_ITEMS+" - Compiles all DSpace items"); + System.out.println(" "+COMMAND_ERASE_COMPILED_ITEMS+" - Erase the OAI compiled items"); + System.out.println("> Parameters:"); + System.out.println(" -v Verbose output"); + System.out.println(" -h Shows this text"); + } + + } +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceDatabaseItem.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceDatabaseItem.java new file mode 100644 index 0000000000..5b88d16b33 --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceDatabaseItem.java @@ -0,0 +1,214 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.xoai.data; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.regex.Pattern; + +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.Item; +import org.dspace.xoai.util.XOAICacheManager; +import org.dspace.xoai.util.XOAIDatabaseManager; + +import com.lyncode.xoai.dataprovider.core.ItemMetadata; +import com.lyncode.xoai.dataprovider.core.ReferenceSet; +import com.lyncode.xoai.dataprovider.data.AbstractAbout; +import com.lyncode.xoai.dataprovider.exceptions.MetadataBindException; +import com.lyncode.xoai.dataprovider.xml.xoai.Element; + +/** + * + * @author Lyncode Development Team + */ +public class DSpaceDatabaseItem extends DSpaceItem +{ + private static Logger log = LogManager.getLogger(DSpaceDatabaseItem.class); + + private static List getSets(Item item) + { + List sets = new ArrayList(); + List coms = new ArrayList(); + try + { + Collection[] itemCollections = item.getCollections(); + for (Collection col : itemCollections) + { + ReferenceSet s = new DSpaceSet(col); + sets.add(s); + for (Community com : XOAIDatabaseManager + .flatParentCommunities(col)) + if (!coms.contains(com)) + coms.add(com); + } + for (Community com : coms) + { + ReferenceSet s = new DSpaceSet(com); + sets.add(s); + } + } + catch (SQLException e) + { + log.error(e.getMessage(), e); + } + return sets; + } + + private Item item; + private List sets; + + public DSpaceDatabaseItem(Item item) + { + this.item = item; + this.sets = getSets(item); + } + + @Override + public List getAbout() + { + return new ArrayList(); + } + + @Override + public Date getDatestamp() + { + return item.getLastModified(); + } + + @Override + public List getSets() + { + return sets; + } + + @Override + public boolean isDeleted() + { + return item.isWithdrawn(); + } + + private static Element getElement(List list, String name) + { + for (Element e : list) + if (name.equals(e.getName())) + return e; + + return null; + } + + private ItemMetadata metadata = null; + + @Override + public ItemMetadata getMetadata() + { + if (metadata == null) + { + try + { + metadata = new ItemMetadata(XOAICacheManager.getCompiledMetadata(this)); + } + catch (MetadataBindException e) + { + log.warn(e.getMessage(), e); + metadata = new ItemMetadata(XOAICacheManager.getMetadata(this)); + } + } + return metadata; + } + + private List getMetadata(List elems, String[] parts) + { + List list = new ArrayList(); + if (parts.length > 1) + { + if (parts[0].equals("*")) + { + for (Element e : elems) + { + if (e.getElement() != null) + list.addAll(this.getMetadata(e.getElement(), + Arrays.copyOfRange(parts, 1, parts.length))); + } + } + else + { + Element e = getElement(elems, parts[0]); + if (e != null) + list.addAll(this.getMetadata(e.getElement(), + Arrays.copyOfRange(parts, 1, parts.length))); + } + } + else if (parts.length == 1) + { + // Here we could have reached our target (named fields) + for (Element e : elems) + { + for (Element.Field f : e.getField()) + { + if (parts[0].equals("*")) + list.add(f.getValue()); + else if (parts[0].equals(f.getName())) + list.add(f.getValue()); + } + } + + if (parts[0].equals("*")) + { + for (Element e : elems) + { + if (e.getElement() != null) + list.addAll(this.getMetadata(e.getElement(), + Arrays.copyOfRange(parts, 1, parts.length))); + } + } + else + { + Element e = getElement(elems, parts[0]); + if (e != null) + list.addAll(this.getMetadata(e.getElement(), + Arrays.copyOfRange(parts, 1, parts.length))); + } + } + else + { + // Here we have reached our target (unnamed fields) + for (Element e : elems) + { + for (Element.Field f : e.getField()) + { + if (f.getName() == null || f.getName().equals("")) + list.add(f.getValue()); + } + } + } + return list; + } + + public List getMetadata(String field) + { + String[] parts = field.split(Pattern.quote(".")); + return getMetadata(this.getMetadata().getMetadata().getElement(), parts); + } + + public Item getItem() + { + return item; + } + + @Override + protected String getHandle() + { + return item.getHandle(); + } +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceIdentify.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceIdentify.java new file mode 100644 index 0000000000..effa722dbe --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceIdentify.java @@ -0,0 +1,148 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.xoai.data; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Context; +import org.dspace.storage.rdbms.DatabaseManager; +import org.dspace.storage.rdbms.TableRowIterator; +import org.dspace.xoai.exceptions.InvalidMetadataFieldException; +import org.dspace.xoai.util.DateUtils; +import org.dspace.xoai.util.MetadataFieldManager; + +import com.lyncode.xoai.dataprovider.core.DeleteMethod; +import com.lyncode.xoai.dataprovider.core.Granularity; +import com.lyncode.xoai.dataprovider.data.AbstractIdentify; + +/** + * + * @author Lyncode Development Team + */ +public class DSpaceIdentify extends AbstractIdentify +{ + private static Logger log = LogManager.getLogger(DSpaceIdentify.class); + + private static List _emails = null; + + private static String _name = null; + + private static String _baseUrl = null; + + private Context _context; + + private HttpServletRequest _request; + + public DSpaceIdentify(Context context, HttpServletRequest request) + { + _context = context; + _request = request; + } + + @Override + public List getAdminEmails() + { + if (_emails == null) + { + _emails = new ArrayList(); + String result = ConfigurationManager.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 + _emails.add(result); + } + return _emails; + } + + @Override + public String getBaseUrl() + { + if (_baseUrl == null) + { + _baseUrl = _request.getRequestURL().toString() + .replace(_request.getPathInfo(), ""); + } + return _baseUrl + _request.getPathInfo(); + } + + @Override + public DeleteMethod getDeleteMethod() + { + return DeleteMethod.PERSISTENT; + } + + @Override + public Date getEarliestDate() + { + // Look at the database! + try + { + TableRowIterator iterator = DatabaseManager + .query(_context, + "SELECT MIN(text_value) as value FROM metadatavalue WHERE metadata_field_id = ?", + MetadataFieldManager.getFieldID(_context, + "dc.date.available")); + + if (iterator.hasNext()) + { + String str = iterator.next().getStringColumn("value"); + try + { + Date d = DateUtils.parseDate(str); + if (d != null) + return d; + } + catch (Exception e) + { + log.error(e.getMessage(), e); + } + } + } + catch (SQLException e) + { + log.error(e.getMessage(), e); + } + catch (InvalidMetadataFieldException e) + { + log.error(e.getMessage(), e); + } + return new Date(); + } + + @Override + public Granularity getGranularity() + { + return Granularity.Second; + } + + @Override + public String getRepositoryName() + { + if (_name == null) + { + _name = ConfigurationManager.getProperty("dspace.name"); + 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; + } + +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceItem.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceItem.java new file mode 100644 index 0000000000..6405722680 --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceItem.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.xoai.data; + +import java.util.ArrayList; +import java.util.List; + +import org.dspace.core.ConfigurationManager; + +import com.lyncode.xoai.dataprovider.data.AbstractAbout; +import com.lyncode.xoai.dataprovider.data.AbstractItem; + +/** + * + * @author Lyncode Development Team + */ +public abstract class DSpaceItem extends AbstractItem +{ + + @Override + public List getAbout() + { + return new ArrayList(); + } + + protected abstract String getHandle (); + + private String _prefix = null; + + @Override + public String getIdentifier() + { + if (_prefix == null) + { + _prefix = ConfigurationManager.getProperty("oai", + "identifier.prefix"); + } + return "oai:" + _prefix + ":" + this.getHandle(); + } +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceItemDatabaseRepository.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceItemDatabaseRepository.java new file mode 100644 index 0000000000..793feacfb5 --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceItemDatabaseRepository.java @@ -0,0 +1,261 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.xoai.data; + +import com.lyncode.xoai.dataprovider.core.ListItemIdentifiersResult; +import com.lyncode.xoai.dataprovider.core.ListItemsResults; +import com.lyncode.xoai.dataprovider.data.AbstractItem; +import com.lyncode.xoai.dataprovider.data.AbstractItemIdentifier; +import com.lyncode.xoai.dataprovider.exceptions.IdDoesNotExistException; +import com.lyncode.xoai.dataprovider.filter.Filter; +import com.lyncode.xoai.dataprovider.filter.FilterScope; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.ItemIterator; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Context; +import org.dspace.handle.HandleManager; +import org.dspace.storage.rdbms.DatabaseManager; +import org.dspace.storage.rdbms.TableRowIterator; +import org.dspace.xoai.filter.DSpaceFilter; +import org.dspace.xoai.filter.DatabaseFilterResult; + +/** + * + * @author Lyncode Development Team + */ +public class DSpaceItemDatabaseRepository extends DSpaceItemRepository +{ + + private static Logger log = LogManager + .getLogger(DSpaceItemDatabaseRepository.class); + + private Context _context; + + public DSpaceItemDatabaseRepository(Context context) + { + _context = context; + } + + @Override + public AbstractItem getItem(String id) throws IdDoesNotExistException + { + try + { + String parts[] = id.split(Pattern.quote(":")); + if (parts.length == 3) + { + DSpaceObject obj = HandleManager.resolveToObject(_context, + parts[2]); + if (obj == null) + throw new IdDoesNotExistException(); + if (!(obj instanceof Item)) + throw new IdDoesNotExistException(); + return new DSpaceDatabaseItem((Item) obj); + } + } + catch (NumberFormatException e) + { + log.debug(e.getMessage(), e); + throw new IdDoesNotExistException(); + } + catch (SQLException e) + { + log.error(e.getMessage(), e); + throw new IdDoesNotExistException(); + } + throw new IdDoesNotExistException(); + } + + private ListItemIdentifiersResult getIdentifierResult(String query, String countQuery, + List countParameters, + List parameters, int length) + { + boolean hasMore = false; + List list = new ArrayList(); + TableRowIterator rows; + int count = -1; + try + { + count = DatabaseManager.querySingle(_context, countQuery, countParameters).getIntColumn("count"); + } + catch (SQLException e1) + { + log.error("Unable to retrieve number of items that match"); + } + try + { + parameters.add(length + 1); + rows = DatabaseManager.queryTable(_context, "item", query, + parameters.toArray()); + ItemIterator iterator = new ItemIterator(_context, rows); + int i = 0; + while (iterator.hasNext() && i < length) + { + list.add(new DSpaceDatabaseItem(iterator.next())); + i++; + } + hasMore = iterator.hasNext(); + } + catch (SQLException e) + { + log.error(e.getMessage(), e); + } + return new ListItemIdentifiersResult(hasMore, list, count); + } + + private ListItemsResults getResult(String query, String countQuery, List countParameters, List parameters, int length) + { + boolean hasMore = false; + List list = new ArrayList(); + TableRowIterator rows; + int count = -1; + try + { + count = DatabaseManager.querySingle(_context, countQuery, countParameters).getIntColumn("count"); + } + catch (SQLException e1) + { + log.error("Unable to retrieve number of items that match"); + } + try + { + + parameters.add(length + 1); + rows = DatabaseManager.queryTable(_context, "item", query, + parameters.toArray()); + ItemIterator iterator = new ItemIterator(_context, rows); + int i = 0; + while (iterator.hasNext() && i < length) + { + list.add(new DSpaceDatabaseItem(iterator.next())); + i++; + } + hasMore = iterator.hasNext(); + } + catch (SQLException e) + { + log.error(e.getMessage(), e); + } + return new ListItemsResults(hasMore, list, count); + } + + @Override + protected ListItemsResults getItems(List filters, int offset, + int length) + { + List parameters = new ArrayList(); + List countParameters = new ArrayList(); + String query = "SELECT i.* FROM item i "; + String countQuery = "SELECT COUNT(*) as count FROM item i"; + List whereCond = new ArrayList(); + for (Filter filter : filters) + { + if (filter.getFilter() instanceof DSpaceFilter) + { + DSpaceFilter dspaceFilter = (DSpaceFilter) filter.getFilter(); + DatabaseFilterResult result = dspaceFilter.getWhere(_context); + if (result.hasResult()) + { + if (filter.getScope() == FilterScope.MetadataFormat) + whereCond.add("(i.withdrawn=TRUE OR (" + + result.getWhere() + "))"); + else + whereCond.add("(" + result.getWhere() + ")"); + parameters.addAll(result.getParameters()); + countParameters.addAll(result.getParameters()); + } + } + } + String where = StringUtils.join(whereCond.iterator(), " AND "); + if (!where.equals("")) { + query += " WHERE " + where; + countQuery += " WHERE " + where; + } + + query += " ORDER BY i.item_id"; + String db = ConfigurationManager.getProperty("db.name"); + boolean postgres = true; + // Assuming Postgres as default + if ("oracle".equals(db)) + postgres = false; + if (postgres) + { + query += " OFFSET ? LIMIT ?"; + } + else + { + // Oracle + query = "SELECT *, ROWNUM r FROM (" + query + + ") WHERE r BETWEEN ? AND ?"; + length = length + offset; + } + parameters.add(offset); + return this.getResult(query, countQuery, countParameters, parameters, length); + } + + @Override + protected ListItemIdentifiersResult getItemIdentifiers( + List filters, int offset, int length) + { + List parameters = new ArrayList(); + List countParameters = new ArrayList(); + String query = "SELECT i.* FROM item i "; + String countQuery = "SELECT COUNT(*) as count FROM item i"; + List whereCond = new ArrayList(); + for (Filter filter : filters) + { + if (filter.getFilter() instanceof DSpaceFilter) + { + DSpaceFilter dspaceFilter = (DSpaceFilter) filter.getFilter(); + DatabaseFilterResult result = dspaceFilter.getWhere(_context); + if (result.hasResult()) + { + if (filter.getScope() == FilterScope.MetadataFormat) + whereCond.add("(i.withdrawn=TRUE OR (" + + result.getWhere() + "))"); + else + whereCond.add("(" + result.getWhere() + ")"); + parameters.addAll(result.getParameters()); + countParameters.addAll(result.getParameters()); + } + } + } + String where = StringUtils.join(whereCond.iterator(), " AND "); + if (!where.equals("")) { + query += " WHERE " + where; + countQuery += " WHERE "+ where; + } + query += " ORDER BY i.item_id"; + String db = ConfigurationManager.getProperty("db.name"); + boolean postgres = true; + // Assuming Postgres as default + if ("oracle".equals(db)) + postgres = false; + if (postgres) + { + query += " OFFSET ? LIMIT ?"; + } + else + { + // Oracle + query = "SELECT *, ROWNUM r FROM (" + query + + ") WHERE r BETWEEN ? AND ?"; + length = length + offset; + } + parameters.add(offset); + return this.getIdentifierResult(query, countQuery, countParameters, parameters, length); + } +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceItemRepository.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceItemRepository.java new file mode 100644 index 0000000000..31030530be --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceItemRepository.java @@ -0,0 +1,164 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.xoai.data; + +import java.util.Date; +import java.util.List; + +import org.dspace.xoai.filter.DateFromFilter; +import org.dspace.xoai.filter.DateUntilFilter; +import org.dspace.xoai.filter.DspaceSetSpecFilter; + +import com.lyncode.xoai.dataprovider.core.ListItemIdentifiersResult; +import com.lyncode.xoai.dataprovider.core.ListItemsResults; +import com.lyncode.xoai.dataprovider.data.AbstractItemRepository; +import com.lyncode.xoai.dataprovider.filter.Filter; +import com.lyncode.xoai.dataprovider.filter.FilterScope; + +/** + * + * @author Lyncode Development Team + */ +public abstract class DSpaceItemRepository extends AbstractItemRepository +{ + + // private static Logger log = + // LogManager.getLogger(DSpaceItemRepository.class); + @Override + protected ListItemIdentifiersResult getItemIdentifiers( + List filters, int offset, int length, Date from) + { + filters.add(new Filter(new DateFromFilter(from), FilterScope.Query)); + return this.getItemIdentifiers(filters, offset, length); + } + + @Override + protected ListItemIdentifiersResult getItemIdentifiers( + List filters, int offset, int length, String setSpec) + { + filters.add(new Filter(new DspaceSetSpecFilter(setSpec), + FilterScope.Query)); + return this.getItemIdentifiers(filters, offset, length); + } + + @Override + protected ListItemIdentifiersResult getItemIdentifiers( + List filters, int offset, int length, Date from, Date until) + { + filters.add(new Filter(new DateFromFilter(from), FilterScope.Query)); + filters.add(new Filter(new DateUntilFilter(until), FilterScope.Query)); + return this.getItemIdentifiers(filters, offset, length); + } + + @Override + protected ListItemIdentifiersResult getItemIdentifiers( + List filters, int offset, int length, String setSpec, + Date from) + { + filters.add(new Filter(new DateFromFilter(from), FilterScope.Query)); + filters.add(new Filter(new DspaceSetSpecFilter(setSpec), + FilterScope.Query)); + return this.getItemIdentifiers(filters, offset, length); + } + + @Override + protected ListItemIdentifiersResult getItemIdentifiers( + List filters, int offset, int length, String setSpec, + Date from, Date until) + { + filters.add(new Filter(new DateFromFilter(from), FilterScope.Query)); + filters.add(new Filter(new DateUntilFilter(until), FilterScope.Query)); + filters.add(new Filter(new DspaceSetSpecFilter(setSpec), + FilterScope.Query)); + return this.getItemIdentifiers(filters, offset, length); + } + + @Override + protected ListItemIdentifiersResult getItemIdentifiersUntil( + List filters, int offset, int length, Date until) + { + filters.add(new Filter(new DateUntilFilter(until), FilterScope.Query)); + return this.getItemIdentifiers(filters, offset, length); + } + + @Override + protected ListItemIdentifiersResult getItemIdentifiersUntil( + List filters, int offset, int length, String setSpec, + Date until) + { + filters.add(new Filter(new DateUntilFilter(until), FilterScope.Query)); + filters.add(new Filter(new DspaceSetSpecFilter(setSpec), + FilterScope.Query)); + return this.getItemIdentifiers(filters, offset, length); + } + + @Override + protected ListItemsResults getItems(List filters, int offset, + int length, Date from) + { + filters.add(new Filter(new DateFromFilter(from), FilterScope.Query)); + return this.getItems(filters, offset, length); + } + + @Override + protected ListItemsResults getItems(List filters, int offset, + int length, String setSpec) + { + filters.add(new Filter(new DspaceSetSpecFilter(setSpec), + FilterScope.Query)); + return this.getItems(filters, offset, length); + } + + @Override + protected ListItemsResults getItems(List filters, int offset, + int length, Date from, Date until) + { + filters.add(new Filter(new DateFromFilter(from), FilterScope.Query)); + filters.add(new Filter(new DateUntilFilter(until), FilterScope.Query)); + return this.getItems(filters, offset, length); + } + + @Override + protected ListItemsResults getItems(List filters, int offset, + int length, String setSpec, Date from) + { + filters.add(new Filter(new DateFromFilter(from), FilterScope.Query)); + filters.add(new Filter(new DspaceSetSpecFilter(setSpec), + FilterScope.Query)); + return this.getItems(filters, offset, length); + } + + @Override + protected ListItemsResults getItems(List filters, int offset, + int length, String setSpec, Date from, Date until) + { + filters.add(new Filter(new DateFromFilter(from), FilterScope.Query)); + filters.add(new Filter(new DateUntilFilter(until), FilterScope.Query)); + filters.add(new Filter(new DspaceSetSpecFilter(setSpec), + FilterScope.Query)); + return this.getItems(filters, offset, length); + } + + @Override + protected ListItemsResults getItemsUntil(List filters, int offset, + int length, Date until) + { + filters.add(new Filter(new DateUntilFilter(until), FilterScope.Query)); + return this.getItems(filters, offset, length); + } + + @Override + protected ListItemsResults getItemsUntil(List filters, int offset, + int length, String setSpec, Date from) + { + filters.add(new Filter(new DateFromFilter(from), FilterScope.Query)); + filters.add(new Filter(new DspaceSetSpecFilter(setSpec), + FilterScope.Query)); + return this.getItems(filters, offset, length); + } +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceItemSolrRepository.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceItemSolrRepository.java new file mode 100644 index 0000000000..966579585f --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceItemSolrRepository.java @@ -0,0 +1,168 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.xoai.data; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.apache.solr.client.solrj.SolrQuery; +import org.apache.solr.common.SolrDocument; +import org.apache.solr.common.SolrDocumentList; +import org.dspace.xoai.filter.DSpaceFilter; +import org.dspace.xoai.filter.SolrFilterResult; +import org.dspace.xoai.solr.DSpaceSolrSearch; +import org.dspace.xoai.solr.exceptions.DSpaceSolrException; +import org.dspace.xoai.solr.exceptions.SolrSearchEmptyException; + +import com.lyncode.xoai.dataprovider.core.ListItemIdentifiersResult; +import com.lyncode.xoai.dataprovider.core.ListItemsResults; +import com.lyncode.xoai.dataprovider.data.AbstractItem; +import com.lyncode.xoai.dataprovider.data.AbstractItemIdentifier; +import com.lyncode.xoai.dataprovider.exceptions.IdDoesNotExistException; +import com.lyncode.xoai.dataprovider.filter.Filter; +import com.lyncode.xoai.dataprovider.filter.FilterScope; + +/** + * + * @author Lyncode Development Team + */ +public class DSpaceItemSolrRepository extends DSpaceItemRepository +{ + private static Logger log = LogManager.getLogger(DSpaceItemSolrRepository.class); + + public DSpaceItemSolrRepository() + { + } + + @Override + public AbstractItem getItem(String identifier) + throws IdDoesNotExistException + { + String parts[] = identifier.split(Pattern.quote(":")); + if (parts.length == 3) + { + try + { + SolrQuery params = new SolrQuery("item.handle:" + parts[2]); + return new DSpaceSolrItem(DSpaceSolrSearch.querySingle(params)); + } + catch (SolrSearchEmptyException ex) + { + throw new IdDoesNotExistException(ex); + } + } + throw new IdDoesNotExistException(); + } + + @Override + protected ListItemIdentifiersResult getItemIdentifiers( + List filters, int offset, int length) + { + List whereCond = new ArrayList(); + for (Filter filter : filters) + { + if (filter.getFilter() instanceof DSpaceFilter) + { + DSpaceFilter dspaceFilter = (DSpaceFilter) filter.getFilter(); + SolrFilterResult result = dspaceFilter.getQuery(); + if (result.hasResult()) + { + if (filter.getScope() == FilterScope.MetadataFormat) + whereCond.add("(item.deleted:true OR (" + + result.getQuery() + "))"); + else + whereCond.add("(" + result.getQuery() + ")"); + } + } + } + if (whereCond.isEmpty()) + whereCond.add("*:*"); + String where = "(" + StringUtils.join(whereCond.iterator(), ") AND (") + + ")"; + return this.getIdentifierResult(where, offset, length); + } + + @Override + protected ListItemsResults getItems(List filters, int offset, + int length) + { + List whereCond = new ArrayList(); + for (Filter filter : filters) + { + if (filter.getFilter() instanceof DSpaceFilter) + { + DSpaceFilter dspaceFilter = (DSpaceFilter) filter.getFilter(); + SolrFilterResult result = dspaceFilter.getQuery(); + if (result.hasResult()) + { + if (filter.getScope() == FilterScope.MetadataFormat) + whereCond.add("(item.deleted:true OR (" + + result.getQuery() + "))"); + else + whereCond.add("(" + result.getQuery() + ")"); + } + } + } + if (whereCond.isEmpty()) + whereCond.add("*:*"); + String where = "(" + StringUtils.join(whereCond.iterator(), ") AND (") + + ")"; + return this.getResult(where, offset, length); + } + + private ListItemsResults getResult(String where, int offset, int length) + { + List list = new ArrayList(); + try + { + SolrQuery params = new SolrQuery(where).setRows(length).setStart( + offset); + SolrDocumentList docs = DSpaceSolrSearch.query(params); + for (SolrDocument doc : docs) + { + list.add(new DSpaceSolrItem(doc)); + } + return new ListItemsResults((docs.getNumFound() > offset + length), + list, (int) docs.getNumFound()); + } + catch (DSpaceSolrException ex) + { + log.error(ex.getMessage(), ex); + return new ListItemsResults(false, list); + } + } + + private ListItemIdentifiersResult getIdentifierResult(String where, + int offset, int length) + { + List list = new ArrayList(); + try + { + SolrQuery params = new SolrQuery(where).setRows(length).setStart( + offset); + boolean hasMore = false; + SolrDocumentList docs = DSpaceSolrSearch.query(params); + hasMore = (offset + length) < docs.getNumFound(); + for (SolrDocument doc : docs) + { + list.add(new DSpaceSolrItem(doc)); + } + return new ListItemIdentifiersResult(hasMore, list, (int) docs.getNumFound()); + } + catch (DSpaceSolrException ex) + { + log.error(ex.getMessage(), ex); + return new ListItemIdentifiersResult(false, list); + } + } + +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceSet.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceSet.java new file mode 100644 index 0000000000..cf9a5148c5 --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceSet.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.xoai.data; + +import org.dspace.content.Collection; +import org.dspace.content.Community; + +import com.lyncode.xoai.dataprovider.core.Set; + +/** + * + * @author Lyncode Development Team + */ +public class DSpaceSet extends Set +{ + public static Set newDSpaceCommunitySet(String handle, String name) + { + return new Set("com_" + handle.replace('/', '_'), name); + } + + public static Set newDSpaceCollectionSet(String handle, String name) + { + return new Set("col_" + handle.replace('/', '_'), name); + } + + public DSpaceSet(Community c) + { + super("com_" + c.getHandle().replace('/', '_'), c.getName()); + } + + public DSpaceSet(Collection c) + { + super("col_" + c.getHandle().replace('/', '_'), c.getName()); + } +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceSetRepository.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceSetRepository.java new file mode 100644 index 0000000000..d2b053909c --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceSetRepository.java @@ -0,0 +1,236 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.xoai.data; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Context; +import org.dspace.storage.rdbms.DatabaseManager; +import org.dspace.storage.rdbms.TableRow; +import org.dspace.storage.rdbms.TableRowIterator; + +import com.lyncode.xoai.dataprovider.core.ListSetsResult; +import com.lyncode.xoai.dataprovider.core.Set; +import com.lyncode.xoai.dataprovider.data.AbstractSetRepository; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.core.Constants; +import org.dspace.handle.HandleManager; + +/** + * + * @author Lyncode Development Team + */ +public class DSpaceSetRepository extends AbstractSetRepository +{ + private static Logger log = LogManager.getLogger(DSpaceSetRepository.class); + + private Context _context; + + public DSpaceSetRepository(Context context) + { + _context = context; + } + + private int getCommunityCount() + { + String query = "SELECT COUNT(*) as count FROM community"; + try + { + TableRowIterator iterator = DatabaseManager.query(_context, query); + if (iterator.hasNext()) + return (int) iterator.next().getLongColumn("count"); + } + catch (SQLException e) + { + log.error(e.getMessage(), e); + } + return 0; + } + + private int getCollectionCount() + { + String query = "SELECT COUNT(*) as count FROM collection"; + try + { + TableRowIterator iterator = DatabaseManager.query(_context, query); + if (iterator.hasNext()) + return (int) iterator.next().getLongColumn("count"); + } + catch (SQLException e) + { + log.error(e.getMessage(), e); + } + return 0; + } + + private List community(int offset, int length) + { + List array = new ArrayList(); + String query = "SELECT community_id, name, handle FROM community c, handle h WHERE h.resource_id=community_id AND h.resource_type_id=? ORDER BY community_id"; + String db = ConfigurationManager.getProperty("db.name"); + boolean postgres = true; + // Assuming postgres as default + if ("oracle".equals(db)) + postgres = false; + if (postgres) + { + query += " OFFSET ? LIMIT ?"; + } + else + { + // ORACLE + query = "SELECT *, ROWNUM r FROM (" + query + + ") WHERE r BETWEEN ? AND ?"; + length = length + offset; + } + try + { + TableRowIterator iterator = DatabaseManager.query(_context, query, + Constants.COMMUNITY, offset, length); + int i = 0; + while (iterator.hasNext() && i < length) + { + TableRow row = iterator.next(); + array.add(DSpaceSet.newDSpaceCommunitySet( + row.getStringColumn("handle"), + row.getStringColumn("name"))); + i++; + } + } + catch (SQLException e) + { + log.error(e.getMessage(), e); + } + return array; + } + + private List collection(int offset, int length) + { + List array = new ArrayList(); + String query = "SELECT collection_id, name, handle FROM collection c, handle h WHERE h.resource_id=collection_id AND h.resource_type_id=? ORDER BY collection_id"; + String db = ConfigurationManager.getProperty("db.name"); + boolean postgres = true; + // Assuming postgres as default + if ("oracle".equals(db)) + postgres = false; + if (postgres) + { + query += " OFFSET ? LIMIT ?"; + } + else + { + // ORACLE + query = "SELECT *, ROWNUM r FROM (" + query + + ") WHERE r BETWEEN ? AND ?"; + length = length + offset; + } + try + { + TableRowIterator iterator = DatabaseManager.query(_context, query, + Constants.COLLECTION, offset, length); + int i = 0; + while (iterator.hasNext() && i < length) + { + TableRow row = iterator.next(); + array.add(DSpaceSet.newDSpaceCollectionSet( + row.getStringColumn("handle"), + row.getStringColumn("name"))); + i++; + } + } + catch (SQLException e) + { + log.error(e.getMessage(), e); + } + return array; + } + + @Override + protected ListSetsResult retrieveSets(int offset, int length) + { + // Only database sets (virtual sets are added by lyncode common library) + log.debug("Quering sets. Offset: " + offset + " - Length: " + length); + List array = new ArrayList(); + int communityCount = this.getCommunityCount(); + log.debug("Communities: " + communityCount); + int collectionCount = this.getCollectionCount(); + log.debug("Collections: " + collectionCount); + + 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 + array.addAll(community(offset, length)); + } + else if (offset < communityCount + collectionCount) + { + array.addAll(collection(offset - communityCount, length)); + } + log.debug("Has More Results: " + + ((offset + length < communityCount + collectionCount) ? "Yes" + : "No")); + return new ListSetsResult(offset + length < communityCount + + collectionCount, array, communityCount + collectionCount); + } + + @Override + public boolean supportSets() + { + return true; + } + + @Override + protected boolean exists(String setSpec) + { + if (setSpec.startsWith("col_")) + { + try + { + DSpaceObject dso = HandleManager.resolveToObject(_context, + setSpec.replace("col_", "").replace("_", "/")); + if (dso == null || !(dso instanceof Collection)) + return false; + return true; + } + catch (Exception ex) + { + log.error(ex.getMessage(), ex); + } + } + else if (setSpec.startsWith("com_")) + { + try + { + DSpaceObject dso = HandleManager.resolveToObject(_context, + setSpec.replace("com_", "").replace("_", "/")); + if (dso == null || !(dso instanceof Community)) + return false; + return true; + } + catch (Exception ex) + { + log.error(ex.getMessage(), ex); + } + } + return false; + } + +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceSolrItem.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceSolrItem.java new file mode 100644 index 0000000000..eb912eb97a --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/data/DSpaceSolrItem.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.xoai.data; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +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; + +/** + * + * @author Lyncode Development Team + */ +public class DSpaceSolrItem extends DSpaceItem +{ + private static Logger log = LogManager + .getLogger(DSpaceSolrItem.class); + + private String unparsedMD; + private ItemMetadata metadata; + private String handle; + private Date lastMod; + private List sets; + private boolean deleted; + + public DSpaceSolrItem (SolrDocument doc) { + unparsedMD = (String) doc.getFieldValue("item.compile"); + handle = (String) doc.getFieldValue("item.handle"); + lastMod = (Date) doc.getFieldValue("item.lastmodified"); + sets = new ArrayList(); + for (Object obj : doc.getFieldValues("item.communities")) + sets.add(new ReferenceSet((String) obj)); + for (Object obj : doc.getFieldValues("item.collections")) + sets.add(new ReferenceSet((String) obj)); + deleted = (Boolean) doc.getFieldValue("item.deleted"); + } + + @Override + public ItemMetadata getMetadata() + { + if (metadata == null) { + metadata = new ItemMetadata(unparsedMD); + } + return metadata; + } + + @Override + public Date getDatestamp() + { + return lastMod; + } + + @Override + public List getSets() + { + return sets; + } + + @Override + public boolean isDeleted() + { + return deleted; + } + + @Override + protected String getHandle() + { + return handle; + } + +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/exceptions/CompilingException.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/exceptions/CompilingException.java new file mode 100644 index 0000000000..ba7dee60e4 --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/exceptions/CompilingException.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.xoai.exceptions; + + +/** + * + * @author Lyncode Development Team + */ +@SuppressWarnings("serial") +public class CompilingException extends Exception +{ + + public CompilingException() + { + } + + public CompilingException(String arg0) + { + super(arg0); + } + + public CompilingException(Throwable arg0) + { + super(arg0); + } + + public CompilingException(String arg0, Throwable arg1) + { + super(arg0, arg1); + } + +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/exceptions/InvalidMetadataFieldException.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/exceptions/InvalidMetadataFieldException.java new file mode 100644 index 0000000000..425f976cbc --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/exceptions/InvalidMetadataFieldException.java @@ -0,0 +1,19 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.xoai.exceptions; + +/** + * + * @author Lyncode Development Team + */ +public class InvalidMetadataFieldException extends Exception +{ + + private static final long serialVersionUID = 5187555092904394914L; + +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DSpaceAtLeastOneMetadataFilter.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DSpaceAtLeastOneMetadataFilter.java new file mode 100644 index 0000000000..22a2b8b63b --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DSpaceAtLeastOneMetadataFilter.java @@ -0,0 +1,257 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +package org.dspace.xoai.filter; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.apache.solr.client.solrj.util.ClientUtils; +import org.dspace.core.Context; +import org.dspace.xoai.data.DSpaceDatabaseItem; +import org.dspace.xoai.exceptions.InvalidMetadataFieldException; +import org.dspace.xoai.filter.data.DSpaceMetadataFilterOperator; +import org.dspace.xoai.util.MetadataFieldManager; + +/** + * + * @author Lyncode Development Team + */ +public class DSpaceAtLeastOneMetadataFilter extends DSpaceFilter +{ + private static Logger log = LogManager + .getLogger(DSpaceAtLeastOneMetadataFilter.class); + + private String _field; + + private DSpaceMetadataFilterOperator _operator = DSpaceMetadataFilterOperator.UNDEF; + + private List _values; + + private String _value; + + private String getField() + { + if (_field == null) + { + _field = super.getParameter("field"); + } + return _field; + } + + @SuppressWarnings("unused") + private String getValue() + { + if (_value == null) + { + _value = super.getParameter("value"); + } + return _value; + } + + private List getValues() + { + if (_values == null) + { + _values = super.getParameters("value"); + } + return _values; + } + + private DSpaceMetadataFilterOperator getOperator() + { + if (_operator == DSpaceMetadataFilterOperator.UNDEF) + { + _operator = DSpaceMetadataFilterOperator.valueOf(super + .getParameter("operator").toUpperCase()); + } + return _operator; + } + + @Override + public DatabaseFilterResult getWhere(Context context) + { + if (this.getField() != null) + { + try + { + int id = MetadataFieldManager.getFieldID(context, + this.getField()); + return this.getWhere(id, this.getValues()); + } + catch (InvalidMetadataFieldException ex) + { + log.error(ex.getMessage(), ex); + } + catch (SQLException ex) + { + log.error(ex.getMessage(), ex); + } + } + return new DatabaseFilterResult(); + } + + @Override + public boolean isShown(DSpaceDatabaseItem item) + { + 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 CONTAINS: + if (praticalValue.contains(theoreticValue)) + return true; + break; + case ENDS_WITH: + if (praticalValue.endsWith(theoreticValue)) + return true; + break; + case EQUAL: + if (praticalValue.equals(theoreticValue)) + return true; + break; + case GREATER: + if (praticalValue.compareTo(theoreticValue) > 0) + return true; + break; + case GREATER_OR_EQUAL: + if (praticalValue.compareTo(theoreticValue) >= 0) + return true; + break; + case LOWER: + if (praticalValue.compareTo(theoreticValue) < 0) + return true; + break; + case LOWER_OR_EQUAL: + if (praticalValue.compareTo(theoreticValue) <= 0) + return true; + break; + } + } + } + return false; + } + + private DatabaseFilterResult getWhere(int mdid, List values) + { + List parts = new ArrayList(); + List params = new ArrayList(); + params.add(mdid); + for (String v : values) + this.buildWhere(v, parts, params); + if (parts.size() > 0) + { + String query = "EXISTS (SELECT tmp.* FROM metadatavalue tmp WHERE tmp.item_id=i.item_id AND tmp.metadata_field_id=?" + + " AND (" + + StringUtils.join(parts.iterator(), " OR ") + + "))"; + return new DatabaseFilterResult(query, params); + } + return new DatabaseFilterResult(); + } + + private void buildWhere(String value, List parts, + List params) + { + switch (this.getOperator()) + { + case CONTAINS: + parts.add("(tmp.text_value LIKE ?)"); + params.add("%" + value + "%"); + break; + case ENDS_WITH: + parts.add("(tmp.text_value LIKE ?)"); + params.add("%" + value); + break; + case STARTS_WITH: + parts.add("(tmp.text_value LIKE ?)"); + params.add(value + "%"); + break; + case EQUAL: + parts.add("(tmp.text_value LIKE ?)"); + params.add(value); + break; + case GREATER: + parts.add("(tmp.text_value > ?)"); + params.add(value); + break; + case LOWER: + parts.add("(tmp.text_value < ?)"); + params.add(value); + break; + case LOWER_OR_EQUAL: + parts.add("(tmp.text_value <= ?)"); + params.add(value); + break; + case GREATER_OR_EQUAL: + parts.add("(tmp.text_value >= ?)"); + params.add(value); + break; + } + } + + @Override + public SolrFilterResult getQuery() + { + String field = this.getField(); + List parts = new ArrayList(); + if (this.getField() != null) + { + for (String v : this.getValues()) + this.buildQuery("metadata." + field, + ClientUtils.escapeQueryChars(v), parts); + if (parts.size() > 0) + { + return new SolrFilterResult(StringUtils.join(parts.iterator(), + " OR ")); + } + } + return new SolrFilterResult(); + } + + private void buildQuery(String field, String value, List parts) + { + switch (this.getOperator()) + { + case CONTAINS: + parts.add("(" + field + ":*" + value + "*)"); + break; + case ENDS_WITH: + parts.add("(" + field + ":*" + value + ")"); + break; + case STARTS_WITH: + parts.add("(" + field + ":" + value + "*)"); + break; + case EQUAL: + parts.add("(" + field + ":" + value + ")"); + break; + case GREATER: + parts.add("(" + field + ":[" + value + " TO *])"); + break; + case LOWER: + parts.add("(" + field + ":[* TO " + value + "])"); + break; + case LOWER_OR_EQUAL: + parts.add("(-(" + field + ":[" + value + " TO *]))"); + break; + case GREATER_OR_EQUAL: + parts.add("(-(" + field + ":[* TO " + value + "]))"); + break; + } + } + +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DSpaceAuthorizationFilter.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DSpaceAuthorizationFilter.java new file mode 100644 index 0000000000..a951699a2e --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DSpaceAuthorizationFilter.java @@ -0,0 +1,75 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +package org.dspace.xoai.filter; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeException; +import org.dspace.authorize.AuthorizeManager; +import org.dspace.content.Bundle; +import org.dspace.content.Item; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.xoai.data.DSpaceDatabaseItem; + +/** + * + * @author Lyncode Development Team + */ +public class DSpaceAuthorizationFilter extends DSpaceFilter +{ + private static Logger log = LogManager + .getLogger(DSpaceAuthorizationFilter.class); + + @Override + public DatabaseFilterResult getWhere(Context context) + { + List params = new ArrayList(); + return new DatabaseFilterResult("EXISTS (SELECT p.action_id FROM " + + "resourcepolicy p, " + "bundle2bitstream b, " + "bundle bu, " + + "item2bundle ib " + "WHERE " + "p.resource_type_id=0 AND " + + "p.resource_id=b.bitstream_id AND " + + "p.epersongroup_id=0 AND " + "b.bundle_id=ib.bundle_id AND " + + "bu.bundle_id=b.bundle_id AND " + "bu.name='ORIGINAL' AND " + + "ib.item_id=i.item_id)", params); + } + + @Override + public boolean isShown(DSpaceDatabaseItem item) + { + try + { + Context ctx = super.getContext(); + Item dsitem = item.getItem(); + AuthorizeManager.authorizeAction(ctx, dsitem, Constants.READ); + for (Bundle b : dsitem.getBundles()) + AuthorizeManager.authorizeAction(ctx, b, Constants.READ); + return true; + } + catch (AuthorizeException ex) + { + log.debug(ex.getMessage()); + } + catch (SQLException ex) + { + log.error(ex.getMessage()); + } + return false; + } + + @Override + public SolrFilterResult getQuery() + { + return new SolrFilterResult("item.public:true"); + } + +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DSpaceFilter.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DSpaceFilter.java new file mode 100644 index 0000000000..50ca86cf5f --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DSpaceFilter.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.xoai.filter; + +import org.dspace.core.Context; +import org.dspace.xoai.data.DSpaceDatabaseItem; + +import com.lyncode.xoai.dataprovider.data.AbstractItemIdentifier; +import com.lyncode.xoai.dataprovider.filter.AbstractFilter; + +/** + * + * @author Lyncode Development Team + */ +public abstract class DSpaceFilter extends AbstractFilter +{ + private Context _ctx = null; + + public void initialize(Context ctx) + { + _ctx = ctx; + } + + public Context getContext() + { + return _ctx; + } + + /** + * Returns null if no where given. Or non empty if some where is given. + * + * @param context + * @param item + * @return + */ + public abstract DatabaseFilterResult getWhere(Context context); + + public abstract SolrFilterResult getQuery(); + + public abstract boolean isShown(DSpaceDatabaseItem item); + + @Override + public boolean isItemShown(AbstractItemIdentifier item) + { + if (item instanceof DSpaceDatabaseItem) + { + return this.isShown((DSpaceDatabaseItem) item); + } + return false; + } +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DSpaceMetadataExistsFilter.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DSpaceMetadataExistsFilter.java new file mode 100644 index 0000000000..9230b7e167 --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DSpaceMetadataExistsFilter.java @@ -0,0 +1,74 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.xoai.filter; + +import java.sql.SQLException; + +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.dspace.core.Context; +import org.dspace.xoai.data.DSpaceDatabaseItem; +import org.dspace.xoai.exceptions.InvalidMetadataFieldException; +import org.dspace.xoai.util.MetadataFieldManager; + +/** + * + * @author Lyncode Development Team + */ +public class DSpaceMetadataExistsFilter extends DSpaceFilter +{ + private static Logger log = LogManager + .getLogger(DSpaceMetadataExistsFilter.class); + + private String _field; + + private String getField() + { + if (this._field == null) + { + _field = super.getParameter("field"); + } + return _field; + } + + @Override + public DatabaseFilterResult getWhere(Context context) + { + try + { + return new DatabaseFilterResult( + "EXISTS (SELECT tmp.* FROM metadatavalue tmp WHERE tmp.item_id=i.item_id AND tmp.metadata_field_id=?)", + MetadataFieldManager.getFieldID(context, this.getField())); + } + catch (InvalidMetadataFieldException e) + { + log.error(e.getMessage(), e); + } + catch (SQLException e) + { + log.error(e.getMessage(), e); + } + return new DatabaseFilterResult(); + } + + @Override + public boolean isShown(DSpaceDatabaseItem item) + { + if (item.getMetadata(this.getField()+".*").size() > 0) + return true; + + return false; + } + + @Override + public SolrFilterResult getQuery() + { + return new SolrFilterResult("metadata." + this.getField() + ":[* TO *]"); + } + +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DatabaseFilterResult.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DatabaseFilterResult.java new file mode 100644 index 0000000000..5f9b726bd5 --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DatabaseFilterResult.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.xoai.filter; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author Lyncode Development Team + */ +public class DatabaseFilterResult +{ + private String _where; + + private List _params; + + private boolean _nothing; + + public DatabaseFilterResult() + { + _nothing = true; + } + + public DatabaseFilterResult(String where, Object... params) + { + _nothing = false; + _where = where; + _params = new ArrayList(); + for (Object obj : params) + _params.add(obj); + } + + public DatabaseFilterResult(String where, List params) + { + _nothing = false; + _where = where; + _params = params; + } + + public boolean hasResult() + { + return !_nothing; + } + + public String getWhere() + { + return _where; + } + + public List getParameters() + { + return _params; + } + +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DateFromFilter.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DateFromFilter.java new file mode 100644 index 0000000000..77fd9594fb --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DateFromFilter.java @@ -0,0 +1,58 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.xoai.filter; + +import java.util.Date; + +import org.apache.solr.client.solrj.util.ClientUtils; +import org.dspace.core.Context; +import org.dspace.xoai.data.DSpaceDatabaseItem; +import org.dspace.xoai.util.DateUtils; + +/** + * + * @author Lyncode Development Team + */ +public class DateFromFilter extends DSpaceFilter +{ + private Date _date; + + public DateFromFilter(Date date) + { + _date = date; + } + + @Override + public DatabaseFilterResult getWhere(Context context) + { + return new DatabaseFilterResult("i.last_modified >= ?", + new java.sql.Date(_date.getTime())); + } + + @Override + public boolean isShown(DSpaceDatabaseItem item) + { + if (item.getDatestamp().compareTo(_date) >= 0) + return true; + return false; + } + + private String dateToString(Date date) + { + return DateUtils.formatToSolr(date); + } + + @Override + public SolrFilterResult getQuery() + { + return new SolrFilterResult("item.lastmodified:[" + + ClientUtils.escapeQueryChars(this.dateToString(_date)) + + " TO *]"); + } + +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DateUntilFilter.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DateUntilFilter.java new file mode 100644 index 0000000000..d4dbb1c91f --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DateUntilFilter.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.xoai.filter; + +import java.text.SimpleDateFormat; +import java.util.Date; +import org.apache.solr.client.solrj.util.ClientUtils; + +import org.dspace.core.Context; +import org.dspace.xoai.data.DSpaceDatabaseItem; + +/** + * + * @author Lyncode Development Team + */ +public class DateUntilFilter extends DSpaceFilter +{ + private Date _date; + + public DateUntilFilter(Date date) + { + _date = date; + } + + @Override + public DatabaseFilterResult getWhere(Context context) + { + return new DatabaseFilterResult("i.last_modified <= ?", + new java.sql.Date(_date.getTime())); + } + + @Override + public boolean isShown(DSpaceDatabaseItem item) + { + if (item.getDatestamp().compareTo(_date) <= 0) + return true; + return false; + } + + private String dateToString(Date date) + { + SimpleDateFormat formatDate = new SimpleDateFormat( + "yyyy-MM-dd'T'HH:mm:ss'Z'"); + return formatDate.format(date); + } + + @Override + public SolrFilterResult getQuery() + { + return new SolrFilterResult("item.lastmodified:[* TO " + + ClientUtils.escapeQueryChars(this.dateToString(_date)) + "]"); + } + +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DspaceSetSpecFilter.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DspaceSetSpecFilter.java new file mode 100644 index 0000000000..b68de7b63b --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/DspaceSetSpecFilter.java @@ -0,0 +1,143 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.xoai.filter; + +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.dspace.core.Context; + +import java.sql.SQLException; +import org.apache.solr.client.solrj.util.ClientUtils; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.handle.HandleManager; +import org.dspace.xoai.data.DSpaceDatabaseItem; +import org.dspace.xoai.util.XOAIDatabaseManager; + +/** + * + * @author Lyncode Development Team + */ +public class DspaceSetSpecFilter extends DSpaceFilter +{ + private static Logger log = LogManager.getLogger(DspaceSetSpecFilter.class); + + private String _setSpec; + + public DspaceSetSpecFilter(String spec) + { + _setSpec = spec; + } + + @Override + public DatabaseFilterResult getWhere(Context context) + { + if (_setSpec.startsWith("col_")) + { + try + { + DSpaceObject dso = HandleManager.resolveToObject(context, + _setSpec.replace("col_", "")); + return new DatabaseFilterResult( + "EXISTS (SELECT tmp.* FROM collection2item tmp WHERE tmp.item_id=i.item_id AND collection_id = ?)", + dso.getID()); + } + catch (Exception ex) + { + log.error(ex.getMessage(), ex); + } + } + else if (_setSpec.startsWith("com_")) + { + try + { + DSpaceObject dso = HandleManager.resolveToObject(context, + _setSpec.replace("com_", "")); + List list = XOAIDatabaseManager.getAllSubCollections( + context, dso.getID()); + String subCollections = StringUtils.join(list.iterator(), ","); + return new DatabaseFilterResult( + "EXISTS (SELECT tmp.* FROM collection2item tmp WHERE tmp.item_id=i.item_id AND collection_id IN (" + + subCollections + "))"); + } + catch (Exception e) + { + log.error(e.getMessage(), e); + } + } + return new DatabaseFilterResult(); + } + + @Override + public boolean isShown(DSpaceDatabaseItem item) + { + try + { + Item dsitem = item.getItem(); + if (_setSpec.startsWith("col_")) + { + String handle = _setSpec.replace("col_", ""); + for (Collection c : dsitem.getCollections()) + if (c.getHandle().replace('/', '_').equals(handle)) + return true; + return false; + } + else if (_setSpec.startsWith("com_")) + { + String handle = _setSpec.replace("com_", ""); + for (Community c : XOAIDatabaseManager + .flatParentCommunities(dsitem)) + if (c.getHandle().replace('/', '_').equals(handle)) + return true; + return false; + } + } + catch (SQLException ex) + { + log.error(ex.getMessage(), ex); + } + + return false; + } + + @Override + public SolrFilterResult getQuery() + { + if (_setSpec.startsWith("col_")) + { + try + { + return new SolrFilterResult("item.collections:" + + ClientUtils.escapeQueryChars(_setSpec)); + } + catch (Exception ex) + { + log.error(ex.getMessage(), ex); + } + } + else if (_setSpec.startsWith("com_")) + { + try + { + return new SolrFilterResult("item.communities:" + + ClientUtils.escapeQueryChars(_setSpec)); + } + catch (Exception e) + { + log.error(e.getMessage(), e); + } + } + return new SolrFilterResult(); + } + +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/SolrFilterResult.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/SolrFilterResult.java new file mode 100644 index 0000000000..662acdd749 --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/SolrFilterResult.java @@ -0,0 +1,41 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.xoai.filter; + +/** + * + * @author Lyncode Development Team + */ +public class SolrFilterResult +{ + + private String _where; + + private boolean _nothing; + + public SolrFilterResult() + { + _nothing = true; + } + + public SolrFilterResult(String query) + { + _nothing = false; + _where = query; + } + + public boolean hasResult() + { + return !_nothing; + } + + public String getQuery() + { + return _where; + } +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/data/DSpaceMetadataFilterOperator.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/data/DSpaceMetadataFilterOperator.java new file mode 100644 index 0000000000..987124d240 --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/filter/data/DSpaceMetadataFilterOperator.java @@ -0,0 +1,17 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +package org.dspace.xoai.filter.data; + +/** + * + * @author Lyncode Development Team + */ +public enum DSpaceMetadataFilterOperator { + UNDEF, CONTAINS, EQUAL, GREATER, LOWER, GREATER_OR_EQUAL, LOWER_OR_EQUAL, ENDS_WITH, STARTS_WITH +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/DSpaceSolrSearch.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/DSpaceSolrSearch.java new file mode 100644 index 0000000000..30205a8fca --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/DSpaceSolrSearch.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.xoai.solr; + +import org.apache.solr.client.solrj.SolrQuery; +import org.apache.solr.client.solrj.SolrQuery.ORDER; +import org.apache.solr.client.solrj.SolrServer; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.response.QueryResponse; +import org.apache.solr.common.SolrDocument; +import org.apache.solr.common.SolrDocumentList; +import org.dspace.xoai.solr.exceptions.DSpaceSolrException; +import org.dspace.xoai.solr.exceptions.SolrSearchEmptyException; + +/** + * + * @author Lyncode Development Team + */ +public class DSpaceSolrSearch +{ + public static SolrDocumentList query(SolrQuery solrParams) + throws DSpaceSolrException + { + try + { + SolrServer server = DSpaceSolrServer.getServer(); + solrParams.addSortField("item.id", ORDER.asc); + QueryResponse response = server.query(solrParams); + return response.getResults(); + } + catch (SolrServerException ex) + { + throw new DSpaceSolrException(ex.getMessage(), ex); + } + } + + public static SolrDocument querySingle(SolrQuery solrParams) + throws SolrSearchEmptyException + { + try + { + SolrServer server = DSpaceSolrServer.getServer(); + solrParams.addSortField("item.id", ORDER.asc); + QueryResponse response = server.query(solrParams); + if (response.getResults().getNumFound() > 0) + return response.getResults().get(0); + else + throw new SolrSearchEmptyException(); + } + catch (SolrServerException ex) + { + throw new SolrSearchEmptyException(ex.getMessage(), ex); + } + } +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/DSpaceSolrServer.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/DSpaceSolrServer.java new file mode 100644 index 0000000000..8bbd49b15c --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/DSpaceSolrServer.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.xoai.solr; + +import java.net.MalformedURLException; + +import org.apache.log4j.LogManager; +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.impl.CommonsHttpSolrServer; +import org.dspace.core.ConfigurationManager; + +/** + * + * @author Lyncode Development Team + */ +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 + { + _server = new CommonsHttpSolrServer( + ConfigurationManager.getProperty("oai", "solr.url")); + log.debug("Solr Server Initialized"); + } + catch (MalformedURLException e) + { + throw new SolrServerException(e); + } + catch (Exception e) + { + log.error(e.getMessage(), e); + } + } + return _server; + } +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/exceptions/DSpaceSolrException.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/exceptions/DSpaceSolrException.java new file mode 100644 index 0000000000..d4c7e5801b --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/exceptions/DSpaceSolrException.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.xoai.solr.exceptions; + +/** + * + * @author Lyncode Development Team + */ +@SuppressWarnings("serial") +public class DSpaceSolrException extends Exception +{ + + /** + * Creates a new instance of DSpaceSolrException without detail + * message. + */ + public DSpaceSolrException() + { + } + + /** + * Constructs an instance of DSpaceSolrException with the + * specified detail message. + * + * @param msg + * the detail message. + */ + public DSpaceSolrException(String msg) + { + super(msg); + } + + public DSpaceSolrException(String msg, Throwable t) + { + super(msg, t); + } +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/exceptions/DSpaceSolrIndexerException.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/exceptions/DSpaceSolrIndexerException.java new file mode 100644 index 0000000000..5b39851311 --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/exceptions/DSpaceSolrIndexerException.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.xoai.solr.exceptions; + +/** + * + * @author Lyncode Development Team + */ +@SuppressWarnings("serial") +public class DSpaceSolrIndexerException extends Exception +{ + /** + * Creates a new instance of DSpaceSolrException without detail + * message. + */ + public DSpaceSolrIndexerException() + { + } + + /** + * Constructs an instance of DSpaceSolrException with the + * specified detail message. + * + * @param msg + * the detail message. + */ + public DSpaceSolrIndexerException(String msg) + { + super(msg); + } + + public DSpaceSolrIndexerException(String msg, Throwable t) + { + super(msg, t); + } +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/exceptions/SolrSearchEmptyException.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/exceptions/SolrSearchEmptyException.java new file mode 100644 index 0000000000..5090ac08cc --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/solr/exceptions/SolrSearchEmptyException.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.xoai.solr.exceptions; + +/** + * + * @author Lyncode Development Team + */ +@SuppressWarnings("serial") +public class SolrSearchEmptyException extends Exception +{ + + /** + * Creates a new instance of SolrSearchEmptyException without + * detail message. + */ + public SolrSearchEmptyException() + { + } + + /** + * Constructs an instance of SolrSearchEmptyException with the + * specified detail message. + * + * @param msg + * the detail message. + */ + public SolrSearchEmptyException(String msg) + { + super(msg); + } + + public SolrSearchEmptyException(String msg, Throwable t) + { + super(msg, t); + } +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/DSpaceDataConvert.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/DSpaceDataConvert.java new file mode 100644 index 0000000000..0d3edcb479 --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/DSpaceDataConvert.java @@ -0,0 +1,36 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.xoai.util; + +import java.util.ArrayList; +import java.util.List; + +import org.dspace.content.DCValue; + +/** + * + * @author Lyncode Development Team + */ +@SuppressWarnings("deprecation") +public class DSpaceDataConvert +{ + public static List getValues(DCValue[] values) + { + List result = new ArrayList(); + for (DCValue dc : values) + result.add(dc.value); + return result; + } + + public static String getValue(DCValue[] values) + { + if (values.length > 0) + return values[0].value; + return null; + } +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/DateUtils.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/DateUtils.java new file mode 100644 index 0000000000..4e161ccc90 --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/DateUtils.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.xoai.util; + +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 + */ +public class DateUtils +{ + + private static Logger log = LogManager.getLogger(DateUtils.class); + + public static String formatToSolr(Date date) + { + // 2008-01-01T00:00:00Z + SimpleDateFormat format = new SimpleDateFormat( + "yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.getDefault()); + format.setTimeZone(TimeZone.getTimeZone("UTC")); + String ret = format.format(date); + return ret; + } + + public static Date parseDate(String date) + { + // 2008-01-01T00:00:00Z + SimpleDateFormat format = new SimpleDateFormat( + "yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.getDefault()); + // format.setTimeZone(TimeZone.getTimeZone("ZULU")); + Date ret; + try + { + ret = format.parse(date); + return ret; + } + catch (ParseException e) + { + format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", + Locale.getDefault()); + try + { + return format.parse(date); + } + catch (ParseException e1) + { + format = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); + try + { + return format.parse(date); + } + catch (ParseException e2) + { + format = new SimpleDateFormat("yyyy-MM", + Locale.getDefault()); + try + { + return format.parse(date); + } + catch (ParseException e3) + { + format = new SimpleDateFormat("yyyy", + Locale.getDefault()); + try + { + return format.parse(date); + } + catch (ParseException e4) + { + log.error(e4.getMessage(), e); + } + } + } + } + } + return new Date(); + } + + public static Date parseFromSolrDate(String date) + { + // 2008-01-01T00:00:00Z + SimpleDateFormat format = new SimpleDateFormat( + "yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.getDefault()); + // format.setTimeZone(TimeZone.getTimeZone("UTC")); + Date ret; + try + { + ret = format.parse(date); + return ret; + } + catch (ParseException e) + { + log.error(e.getMessage(), e); + } + return new Date(); + } +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/ItemUtils.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/ItemUtils.java new file mode 100644 index 0000000000..c81de00931 --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/ItemUtils.java @@ -0,0 +1,311 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.xoai.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; +import java.util.List; + +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Bitstream; +import org.dspace.content.Bundle; +import org.dspace.content.DCValue; +import org.dspace.content.Item; +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.DSpaceDatabaseItem; + +import com.lyncode.xoai.dataprovider.util.Base64Utils; +import com.lyncode.xoai.dataprovider.xml.xoai.Element; +import com.lyncode.xoai.dataprovider.xml.xoai.Metadata; +import com.lyncode.xoai.dataprovider.xml.xoai.ObjectFactory; + +/** + * + * @author Lyncode Development Team + */ +@SuppressWarnings("deprecation") +public class ItemUtils +{ + private static Logger log = LogManager + .getLogger(ItemUtils.class); + + 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(ObjectFactory factory, String name) + { + Element e = factory.createElement(); + e.setName(name); + return e; + } + + private static Element.Field createValue(ObjectFactory factory, String value) + { + Element.Field e = factory.createElementField(); + e.setValue(value); + return e; + } + + private static Element.Field createValue(ObjectFactory factory, + String name, String value) + { + Element.Field e = factory.createElementField(); + e.setValue(value); + e.setName(name); + return e; + } + public static Metadata retrieveMetadata (Item item) { + Metadata metadata; + + DSpaceDatabaseItem dspaceItem = new DSpaceDatabaseItem(item); + + // read all metadata into Metadata Object + ObjectFactory factory = new ObjectFactory(); + metadata = factory.createMetadata(); + DCValue[] vals = item.getMetadata(Item.ANY, Item.ANY, Item.ANY, Item.ANY); + for (DCValue val : vals) + { + Element valueElem = null; + Element schema = getElement(metadata.getElement(), val.schema); + if (schema == null) + { + schema = create(factory, val.schema); + metadata.getElement().add(schema); + } + valueElem = schema; + + // Has element.. with XOAI one could have only schema and value + if (val.element != null && !val.element.equals("")) + { + Element element = getElement(schema.getElement(), + val.element); + if (element == null) + { + element = create(factory, val.element); + schema.getElement().add(element); + } + valueElem = element; + + // Qualified element? + if (val.qualifier != null && !val.qualifier.equals("")) + { + Element qualifier = getElement(element.getElement(), + val.qualifier); + if (qualifier == null) + { + qualifier = create(factory, val.qualifier); + element.getElement().add(qualifier); + } + valueElem = qualifier; + } + } + + // Language? + if (val.language != null && !val.language.equals("")) + { + Element language = getElement(valueElem.getElement(), + val.language); + if (language == null) + { + language = create(factory, val.language); + valueElem.getElement().add(language); + } + valueElem = language; + } + else + { + Element language = getElement(valueElem.getElement(), + "none"); + if (language == null) + { + language = create(factory, "none"); + valueElem.getElement().add(language); + } + valueElem = language; + } + + valueElem.getField().add(createValue(factory, "value", val.value)); + if (val.authority != null) { + valueElem.getField().add(createValue(factory, "authority", val.authority)); + if (val.confidence != Choices.CF_NOVALUE) + valueElem.getField().add(createValue(factory, "confidence", val.confidence + "")); + } + } + // Done! Metadata has been read! + // Now adding bitstream info + Element bundles = create(factory, "bundles"); + metadata.getElement().add(bundles); + + Bundle[] bs; + try + { + bs = item.getBundles(); + for (Bundle b : bs) + { + Element bundle = create(factory, "bundle"); + bundles.getElement().add(bundle); + bundle.getField() + .add(createValue(factory, "name", b.getName())); + + Element bitstreams = create(factory, "bitstreams"); + bundle.getElement().add(bitstreams); + Bitstream[] bits = b.getBitstreams(); + for (Bitstream bit : bits) + { + Element bitstream = create(factory, "bitstream"); + bitstreams.getElement().add(bitstream); + String url = ""; + String bsName = bitstream.getName(); + String sid = String.valueOf(bit.getSequenceID()); + String baseUrl = ConfigurationManager.getProperty("oai", + "bitstream.baseUrl"); + String handle = null; + // get handle of parent Item of this bitstream, if there + // is one: + Bundle[] bn = bit.getBundles(); + if (bn.length > 0) + { + Item bi[] = bn[0].getItems(); + if (bi.length > 0) + { + handle = bi[0].getHandle(); + } + } + if (bsName == null) + { + String ext[] = bit.getFormat().getExtensions(); + bsName = "bitstream_" + sid + + (ext.length > 0 ? ext[0] : ""); + } + if (handle != null && baseUrl != null) + { + url = baseUrl + "/bitstream/" + + URLUtils.encode(handle) + "/" + + sid + "/" + + URLUtils.encode(bsName); + } + else + { + url = URLUtils.encode(bsName); + } + + String cks = bit.getChecksum(); + String cka = bit.getChecksumAlgorithm(); + String oname = bit.getSource(); + String name = bit.getName(); + + if (name != null) + bitstream.getField().add( + createValue(factory, "name", name)); + if (oname != null) + bitstream.getField().add( + createValue(factory, "originalName", name)); + bitstream.getField().add( + createValue(factory, "format", bit.getFormat() + .getMIMEType())); + bitstream.getField().add( + createValue(factory, "size", "" + bit.getSize())); + bitstream.getField().add(createValue(factory, "url", url)); + bitstream.getField().add( + createValue(factory, "checksum", cks)); + bitstream.getField().add( + createValue(factory, "checksumAlgorithm", cka)); + bitstream.getField().add( + createValue(factory, "sid", bit.getSequenceID() + + "")); + } + } + } + catch (SQLException e1) + { + e1.printStackTrace(); + } + + + // Other info + Element other = create(factory, "others"); + + other.getField().add( + createValue(factory, "handle", item.getHandle())); + other.getField().add( + createValue(factory, "identifier", dspaceItem.getIdentifier())); + other.getField().add( + createValue(factory, "lastModifyDate", item + .getLastModified().toString())); + metadata.getElement().add(other); + + // Repository Info + Element repository = create(factory, "repository"); + repository.getField().add( + createValue(factory, "name", + ConfigurationManager.getProperty("dspace.name"))); + repository.getField().add( + createValue(factory, "mail", + ConfigurationManager.getProperty("mail.admin"))); + metadata.getElement().add(repository); + + // Licensing info + Element license = create(factory, "license"); + Bundle[] licBundles; + try + { + licBundles = item.getBundles(Constants.LICENSE_BUNDLE_NAME); + if (licBundles.length > 0) + { + Bundle licBundle = licBundles[0]; + Bitstream[] licBits = licBundle.getBitstreams(); + if (licBits.length > 0) + { + Bitstream licBit = licBits[0]; + InputStream in; + try + { + in = licBit.retrieve(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Utils.bufferedCopy(in, out); + license.getField().add( + createValue(factory, "bin", + Base64Utils.encode(out.toString()))); + metadata.getElement().add(license); + } + catch (AuthorizeException e) + { + log.warn(e.getMessage(), e); + } + catch (IOException e) + { + log.warn(e.getMessage(), e); + } + catch (SQLException e) + { + log.warn(e.getMessage(), e); + } + + } + } + } + catch (SQLException e1) + { + log.warn(e1.getMessage(), e1); + } + + return metadata; + } +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/MetadataFieldManager.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/MetadataFieldManager.java new file mode 100644 index 0000000000..877582b3a1 --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/MetadataFieldManager.java @@ -0,0 +1,106 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.xoai.util; + +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +import org.dspace.core.Context; +import org.dspace.storage.rdbms.DatabaseManager; +import org.dspace.storage.rdbms.TableRowIterator; +import org.dspace.xoai.exceptions.InvalidMetadataFieldException; + +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; + +/** + * + * @author Lyncode Development Team + */ +public class MetadataFieldManager +{ + private static Logger log = LogManager + .getLogger(MetadataFieldManager.class); + + private static MetadataFieldManager _manager = null; + + public static int getFieldID(Context context, String field) + throws InvalidMetadataFieldException, SQLException + { + if (_manager == null) + _manager = new MetadataFieldManager(); + if (!_manager.hasField(field)) + { + String[] pieces = field.split(Pattern.quote(".")); + if (pieces.length > 1) + { + String schema = pieces[0]; + String element = pieces[1]; + String qualifier = null; + if (pieces.length > 2) + qualifier = pieces[2]; + String query = "SELECT mfr.metadata_field_id as mid FROM metadatafieldregistry mfr, " + + "metadataschemaregistry msr WHERE mfr.metadata_schema_id=mfr.metadata_schema_id AND " + + "msr.short_id = ? AND mfr.element = ?"; + + TableRowIterator iterator; + + if (qualifier == null) + { + query += " AND mfr.qualifier is NULL"; + log.debug("Query: " + query); + iterator = DatabaseManager.query(context, query, schema, + element); + } + else + { + log.debug("Qualifier: " + qualifier); + query += " AND mfr.qualifier = ?"; + log.debug("Query: " + query); + iterator = DatabaseManager.query(context, query, schema, + element, qualifier); + } + + if (iterator.hasNext()) + { + _manager.add(field, iterator.next().getIntColumn("mid")); + } + else + throw new InvalidMetadataFieldException(); + + } + else + throw new InvalidMetadataFieldException(); + } + return _manager.getField(field); + } + + private Map _map; + + private MetadataFieldManager() + { + _map = new HashMap(); + } + + public boolean hasField(String field) + { + return _map.containsKey(field); + } + + public int getField(String field) + { + return _map.get(field).intValue(); + } + + public void add(String field, int id) + { + _map.put(field, new Integer(id)); + } +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/URLUtils.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/URLUtils.java new file mode 100644 index 0000000000..b5bdfef0d8 --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/URLUtils.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.xoai.util; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; + +/** + * + * @author Lyncode Development Team + */ +public class URLUtils +{ + private static Logger log = LogManager + .getLogger(URLUtils.class); + public static String encode (String value) { + try + { + return URLEncoder.encode(value, "UTF-8"); + } + catch (UnsupportedEncodingException e) + { + log.warn(e.getMessage(), e); + return value; + } + } +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/XOAICacheManager.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/XOAICacheManager.java new file mode 100644 index 0000000000..dee74c939b --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/XOAICacheManager.java @@ -0,0 +1,367 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.xoai.util; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.dspace.content.Item; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Utils; +import org.dspace.xoai.data.DSpaceDatabaseItem; + +import com.lyncode.xoai.dataprovider.OAIDataProvider; +import com.lyncode.xoai.dataprovider.OAIRequestParameters; +import com.lyncode.xoai.dataprovider.core.XOAIManager; +import com.lyncode.xoai.dataprovider.exceptions.MetadataBindException; +import com.lyncode.xoai.dataprovider.exceptions.OAIException; +import com.lyncode.xoai.dataprovider.util.Base64Utils; +import com.lyncode.xoai.dataprovider.util.MarshallingUtils; +import com.lyncode.xoai.dataprovider.xml.xoai.Metadata; + +/** + * + * @author Lyncode Development Team + */ +public class XOAICacheManager +{ + private static Logger log = LogManager.getLogger(XOAICacheManager.class); + + private static final String ITEMDIR = File.separator + "items"; + + private static final String REQUESTDIR = File.separator + "requests"; + + private static final String DATEFILE = File.separator + "date.file"; + + private static String baseDir = null; + + private static String getBaseDir() + { + if (baseDir == null) + { + String dir = ConfigurationManager.getProperty("oai", "cache.dir"); + baseDir = dir; + } + return baseDir; + } + + private static File getCachedResponseFile(String id) + { + File dir = new File(getBaseDir() + REQUESTDIR); + if (!dir.exists()) + dir.mkdirs(); + + String name = File.separator + Base64Utils.encode(id); + return new File(getBaseDir() + REQUESTDIR + name); + } + + private static File getMetadataCache(Item item) + { + File dir = new File(getBaseDir() + ITEMDIR); + if (!dir.exists()) + dir.mkdirs(); + + String name = File.separator + item.getHandle().replace('/', '_'); + return new File(getBaseDir() + ITEMDIR + name); + } + + public static void compileItem(DSpaceDatabaseItem item) + { + File metadataCache = getMetadataCache(item.getItem()); + if (metadataCache.exists()) + metadataCache.delete(); + getMetadata(item); + } + + public static String getCompiledMetadata(DSpaceDatabaseItem item) + throws MetadataBindException + { + log.debug("Trying to find compiled item"); + File metadataCache = getMetadataCache(item.getItem()); + Metadata metadata; + String compiled; + if (!metadataCache.exists()) + { + log.debug("This is not a compiled item"); + // generate cache + metadata = ItemUtils.retrieveMetadata(item.getItem()); + FileOutputStream output; + try + { + output = new FileOutputStream(metadataCache); + MarshallingUtils.writeMetadata(output, metadata); + } + catch (FileNotFoundException e) + { + log.warn( + "Could not open file for writing: " + + metadataCache.getPath(), e); + } + catch (MetadataBindException e) + { + log.warn("Unable to export in-memory metadata into file: " + + metadataCache.getPath(), e); + } + } + log.debug("This is a compiled item!"); + // Read compiled file + FileInputStream input; + try + { + input = new FileInputStream(metadataCache); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + Utils.bufferedCopy(input, output); + input.close(); + output.close(); + compiled = output.toString(); + } + catch (Exception e) + { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + log.warn(e.getMessage(), e); + MarshallingUtils.writeMetadata(output, + ItemUtils.retrieveMetadata(item.getItem())); + compiled = output.toString(); + } + return compiled; + } + + public static Metadata getMetadata(DSpaceDatabaseItem item) + { + log.debug("Trying to find compiled item"); + File metadataCache = getMetadataCache(item.getItem()); + Metadata metadata; + if (!metadataCache.exists()) + { + log.debug("This is not a compiled item"); + // generate cache + metadata = ItemUtils.retrieveMetadata(item.getItem()); + FileOutputStream output; + try + { + output = new FileOutputStream(metadataCache); + MarshallingUtils.writeMetadata(output, metadata); + } + catch (FileNotFoundException e) + { + log.warn( + "Could not open file for writing: " + + metadataCache.getPath(), e); + } + catch (MetadataBindException e) + { + log.warn("Unable to export in-memory metadata into file: " + + metadataCache.getPath(), e); + } + } + else + { + log.debug("This is a compiled item!"); + // Read compiled file + FileInputStream input; + try + { + input = new FileInputStream(metadataCache); + metadata = MarshallingUtils.readMetadata(input); + input.close(); + } + catch (Exception e) + { + log.warn(e.getMessage(), e); + metadata = ItemUtils.retrieveMetadata(item.getItem()); + } + } + return metadata; + } + + private static String getStaticHead() + { + return "" + + ((XOAIManager.getManager().hasStyleSheet()) ? ("") + : "") + + ""; + } + + public static void handle(String identification, + OAIDataProvider dataProvider, OAIRequestParameters parameters, + OutputStream out) throws IOException + { + + boolean caching = ConfigurationManager.getBooleanProperty("oai", "cache.enabled", true); + File cachedResponse = getCachedResponseFile(identification); + if (!caching || !cachedResponse.exists()) + { + log.debug("[XOAI] Result not cached"); + try + { + // XOAI response facade + // This in-memory buffer will be used to store the XOAI response + ByteArrayOutputStream intermediate = new ByteArrayOutputStream(); + dataProvider.handle(parameters, intermediate); + String xoaiResponse = intermediate.toString(); + + // Cutting the header (to allow one to change the response time) + String end = ""; + int pos = xoaiResponse.indexOf(end); + if (pos > 0) + xoaiResponse = xoaiResponse.substring(pos + (end.length())); + + // Storing in a file + FileOutputStream output = new FileOutputStream(cachedResponse); + output.write(xoaiResponse.getBytes()); + output.flush(); + output.close(); + } + catch (OAIException e) + { + // try to remove the file (If an error occurs, it must not show + // empty pages) + if (cachedResponse.exists()) + cachedResponse.delete(); + log.error(e.getMessage(), e); + } + } + else + log.debug("[OAI 2.0] Cached Result"); + + // The cached file is written, now one start by adding the header + SimpleDateFormat format = new SimpleDateFormat( + "yyyy-MM-dd'T'HH:mm:ss'Z'"); + out.write((getStaticHead() + "" + + format.format(new Date()) + "").getBytes()); + + // Now just simply copy the compiled file + FileInputStream in = new FileInputStream(cachedResponse); + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) + { + out.write(buf, 0, len); + } + in.close(); + } + + private static final SimpleDateFormat format = new SimpleDateFormat(); + + public static Date getLastCompilationDate() + { + FileInputStream fstream; + + try + { + fstream = new FileInputStream(getBaseDir() + DATEFILE); + // Get the object of DataInputStream + DataInputStream in = new DataInputStream(fstream); + BufferedReader br = new BufferedReader(new InputStreamReader(in)); + try + { + Date d = format.parse(br.readLine()); + return d; + } + catch (Exception e) + { + log.debug(e.getMessage(), e); + try + { + fstream.close(); + return null; + } + catch (Exception e1) + { + log.debug(e1.getMessage(), e1); + return null; + } + } + } + catch (FileNotFoundException e) + { + log.debug(e.getMessage(), e); + return null; + } + } + + public static void main(String... args) + { + FileOutputStream fstream; + try + { + fstream = new FileOutputStream("test"); + // Get the object of DataInputStream + fstream.write(format.format(new Date()).getBytes()); + fstream.flush(); + fstream.close(); + } + catch (Exception e) + { + e.printStackTrace(); + } + System.out.println(format.format(new Date())); + } + + public static void setLastCompilationDate(Date date) + { + FileOutputStream fstream; + try + { + fstream = new FileOutputStream(getBaseDir() + DATEFILE); + // Get the object of DataInputStream + fstream.write(format.format(date).getBytes()); + fstream.flush(); + fstream.close(); + } + catch (Exception e) + { + log.debug("Error writing the date"); + } + } + + public static void deleteCachedResponses() + { + File directory = new File(getBaseDir() + REQUESTDIR); + if (directory.exists()) + { + // Get all files in directory + File[] files = directory.listFiles(); + for (File file : files) + { + // Delete each file + file.delete(); + } + } + } + + public static void deleteCompiledItems() + { + (new File(getBaseDir() + DATEFILE)).delete(); + File directory = new File(getBaseDir() + ITEMDIR); + if (directory.exists()) + { + // Get all files in directory + File[] files = directory.listFiles(); + for (File file : files) + { + // Delete each file + file.delete(); + } + } + } +} diff --git a/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/XOAIDatabaseManager.java b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/XOAIDatabaseManager.java new file mode 100644 index 0000000000..a584f792a6 --- /dev/null +++ b/dspace-oai/dspace-oai-api/src/main/java/org/dspace/xoai/util/XOAIDatabaseManager.java @@ -0,0 +1,108 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.xoai.util; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.Item; +import org.dspace.core.Context; + +/** + * + * @author Lyncode Development Team + */ +public class XOAIDatabaseManager +{ + public static List getAllSubCollections(Context ct, int i) + throws SQLException + { + Queue comqueue = new LinkedList(); + List list = new ArrayList(); + comqueue.add(Community.find(ct, i)); + while (!comqueue.isEmpty()) + { + Community c = comqueue.poll(); + for (Community sub : c.getSubcommunities()) + comqueue.add(sub); + for (Collection col : c.getCollections()) + if (!list.contains(col)) + list.add(col.getID()); + } + return list; + } + + public static List flatParentCommunities(Collection c) + throws SQLException + { + Queue queue = new LinkedList(); + List result = new ArrayList(); + for (Community com : c.getCommunities()) + queue.add(com); + + while (!queue.isEmpty()) + { + Community p = queue.poll(); + Community par = p.getParentCommunity(); + if (par != null) + queue.add(par); + if (!result.contains(p)) + result.add(p); + } + + return result; + } + + public static List flatParentCommunities(Community c) + throws SQLException + { + Queue queue = new LinkedList(); + List result = new ArrayList(); + + queue.add(c); + + while (!queue.isEmpty()) + { + Community p = queue.poll(); + Community par = p.getParentCommunity(); + if (par != null) + queue.add(par); + if (!result.contains(p)) + result.add(p); + } + + return result; + } + + public static List flatParentCommunities(Item c) + throws SQLException + { + Queue queue = new LinkedList(); + List result = new ArrayList(); + + for (Community com : c.getCommunities()) + queue.add(com); + + while (!queue.isEmpty()) + { + Community p = queue.poll(); + Community par = p.getParentCommunity(); + if (par != null) + queue.add(par); + if (!result.contains(p)) + result.add(p); + } + + return result; + } +} diff --git a/dspace-oai/dspace-oai-webapp/pom.xml b/dspace-oai/dspace-oai-webapp/pom.xml index 8bc58ddd53..ceb4009ca7 100644 --- a/dspace-oai/dspace-oai-webapp/pom.xml +++ b/dspace-oai/dspace-oai-webapp/pom.xml @@ -1,115 +1,108 @@ - - 4.0.0 - org.dspace - dspace-oai-webapp - war - DSpace OAI :: Web Application Resources - DSpace OAI Service Provider Webapplication Resources + + + 4.0.0 - - - org.dspace - dspace-oai - 3.0-SNAPSHOT - .. - - - - - ${basedir}/../../${filters.file} - - - - - ${basedir} - true - - src/main/webapp/WEB-INF/web.xml - - - - - ${basedir} - false - - src/main/webapp/WEB-INF/web.xml - - - - - - - org.apache.maven.plugins - maven-war-plugin - - false - - WEB-INF/lib/*.jar - WEB-INF/lib/*.jar - - - - prepare-package - - - - - com.mycila.maven-license-plugin - maven-license-plugin - - - **/*.LICENSE - src/main/webapp/oai2.xsl - - - - - + + dspace-oai + org.dspace + 3.0-SNAPSHOT + - - - oracle-support - - - db.name - oracle - - - - - com.oracle - ojdbc6 - - - - - postgres-support - - - !db.name - - - - - postgresql - postgresql - - - - + dspace-oai-webapp + war - - - org.dspace - dspace-api - - - org.dspace - dspace-oai-api - - + DSpace OAI 2.0 :: Web Application Resources + Webapp + + + + org.apache.maven.plugins + maven-war-plugin + + false + + WEB-INF/lib/*.jar + WEB-INF/lib/*.jar + + + true + ${basedir}/src/main/webapp + + WEB-INF/web.xml + + + + + + + prepare-package + + + + + + + + + + + dspace.config + + + + + ${dspace.config} + + + + + oracle-support + + + db.name + oracle + + + + + com.oracle + ojdbc6 + + + + + postgres-support + + + !db.name + + + + + postgresql + postgresql + + + + + + + + org.dspace + dspace-oai-api + ${project.version} + + + + + + DSpace @ Lyncode + dspace@lyncode.com + Lyncode + http://www.lyncode.com + + diff --git a/dspace-oai/dspace-oai-webapp/src/main/webapp/WEB-INF/web.xml b/dspace-oai/dspace-oai-webapp/src/main/webapp/WEB-INF/web.xml index b0656b8134..05af10781d 100644 --- a/dspace-oai/dspace-oai-webapp/src/main/webapp/WEB-INF/web.xml +++ b/dspace-oai/dspace-oai-webapp/src/main/webapp/WEB-INF/web.xml @@ -1,4 +1,4 @@ - + - + + + XOAI Data Provider + + + + The location of the main DSpace configuration file + + dspace-config + ${dspace.dir}/config/dspace.cfg + + + + + The location of the main DSpace configuration file + + dspace.dir + ${dspace.dir} + + + + + org.dspace.app.util.DSpaceContextListener + + + + + oai + org.dspace.xoai.DSpaceOAIDataProvider + + + + default + /static/* + + + + oai + /* + - - - - DSpace OAI-PMH 2.0 - - - - dspace-config - ${dspace.dir}/config/dspace.cfg - - The location of the main DSpace configuration file - - - - - properties - ${dspace.dir}/config/oaicat.properties - - The location of the oaicat.properties file containing - datapairs used to initialize the OAI repository software. - - - - - - - The location of the main DSpace configuration file - - dspace.dir - ${dspace.dir} - - - - - - org.dspace.app.util.DSpaceContextListener - - - - - oai-handler - ORG.oclc.oai.server.OAIHandler - - - - default - *.xsl - - - - oai-handler - /request - diff --git a/dspace-oai/dspace-oai-webapp/src/main/webapp/oai2.xsl b/dspace-oai/dspace-oai-webapp/src/main/webapp/oai2.xsl deleted file mode 100644 index 3848fdb9f3..0000000000 --- a/dspace-oai/dspace-oai-webapp/src/main/webapp/oai2.xsl +++ /dev/null @@ -1,770 +0,0 @@ - - - - - - - - - - - - - - - -td.value { - vertical-align: top; - padding-left: 1em; - padding: 3px; -} -td.key { - background-color: #e0e0ff; - padding: 3px; - text-align: right; - border: 1px solid #c0c0c0; - white-space: nowrap; - font-weight: bold; - vertical-align: top; -} -.result-count { - margin-top:10px; - background-color: #e0e0ff; - padding: 3px; - border: 1px solid #c0c0c0; - white-space: nowrap; - font-weight: bold; - vertical-align: top; -} -.dcdata td.key { - background-color: #ffffe0; -} -body { - margin: 1em 2em 1em 2em; -} -h1, h2, h3 { - font-family: sans-serif; - clear: left; -} -h1 { - padding-bottom: 4px; - margin-bottom: 0px; -} -h2 { - margin-bottom: 0.5em; -} -h3 { - margin-bottom: 0.3em; - font-size: medium; -} -.link { - border: 1px outset #88f; - background-color: #c0c0ff; - padding: 1px 4px 1px 4px; - font-size: 80%; - text-decoration: none; - font-weight: bold; - font-family: sans-serif; - color: black; -} -.link:hover { - color: red; -} -.link:active { - color: red; - border: 1px inset #88f; - background-color: #a0a0df; -} -.oaiRecord, .oaiRecordTitle { - background-color: #f0f0ff; - border-style: solid; - border-color: #d0d0d0; -} -h2.oaiRecordTitle { - background-color: #e0e0ff; - font-size: medium; - font-weight: bold; - padding: 10px; - border-width: 2px 2px 0px 2px; - margin: 0px; -} -.oaiRecord { - margin-bottom: 3em; - border-width: 2px; - padding: 10px; -} - -.results { - margin-bottom: 1.5em; -} -ul.quicklinks { - margin-top: 2px; - padding: 4px; - text-align: left; - border-bottom: 2px solid #ccc; - border-top: 2px solid #ccc; - clear: left; -} -ul.quicklinks li { - font-size: 80%; - display: inline; - list-stlye: none; - font-family: sans-serif; -} -p.intro { - font-size: 80%; -} -/* Order in HTML must be: verb, arguments. The displayed order is reversed here to conventional: arguments, verb. */ -#form1, #form2, #form3 { - position: relative; -} -#form1div { - position: relative; - top: 7.5em; -} -#form2div { - position: relative; - top: 1.5em; -} -#form3div { - position: relative; - top: 3.5em; -} -#form1table, #form2table, #form3table { - position: relative; - top: -2em; -} -.value-error { - background: #FF9999; - text-align: left; -} - - - - - - - - - OAI 2.0 Request Results - - - -

OAI 2.0 Request Results

- -

You are viewing an HTML version of the XML OAI response. To see the underlying XML use your web browsers view source option. More information about this XSLT is at the bottom of the page.

- - -

About the XSLT

-

An XSLT file has converted the OAI-PMH 2.0 responses into XHTML which looks nice in a browser which supports XSLT such as Mozilla, Firebird and Internet Explorer. The XSLT file was created by Christopher Gutteridge at the University of Southampton as part of the GNU EPrints system, and is freely redistributable under the GPL.

If you want to use the XSL file on your own OAI interface you may but due to the way XSLT works you must install the XSL file on the same server as the OAI script, you can't just link to this copy.

For more information or to download the XSL file please see the OAI to XHTML XSLT homepage.

- - - - -
- - - - - - - - - - - - - - -
Datestamp of response
Request base URL
Request verb
- - -

OAI Error(s)

-

The request could not be completed due to the following error or errors.

-
- -
- -

For your convenience, here's a form with possible combinations of arguments (required arguments are in bold text):

-
-
- - -
- - - - - -
metadataPrefix:
set:
from:(YYYY-MM-DD)
until:(YYYY-MM-DD)
-
-

Alternatively, you can provide only the resumptionToken:

-
-
- - -
- - -
resumptionToken:
-
-

Or you can get a single record:

-
-
- -
- - - -
metadataPrefix:
identifier:
-
-
-
- -

-
- - - - - - -
-
-
-
- - - - - - - - -
Error Code
-

-
- - - - - - - - - - - - - - - - - - -
Repository Name
Base URL
Protocol Version
Earliest Datestamp
Deleted Record Policy
Granularity
- - -
- - - Admin Email - - - - - - - - -

Description: Toolkit

- - - - - - - - - - - -
Title
Author
Version
URL
Icon
-
- -

Unsupported Description Type

-

The XSL currently does not support this type of description.

-
- -
-
-
-
- - - - - -

OAI-Identifier

- - - - - - - - - -
Scheme
Repository Identifier
Delimiter
Sample OAI Identifier
-
- - - - - -

EPrints Description

- -

Content

- -
- -

Submission Policy

- -
-

Metadata Policy

- -

Data Policy

- - -
- - - -

-
- -
-
-
- - -

Comment

-
-
- - - - - -

Friends

-
    - -
-
- - -
  • - -Identify
  • -
    - - - - - -

    Branding

    - - -
    - - -

    Icon

    - - - {br:title} - - - {br:title} - - -
    - - -

    Metadata Rendering Rule

    - - - - - - - -
    URL
    Namespace
    Mime Type
    -
    - - - - - - -

    Gateway Information

    - - - - - - - - - - - - - - -
    Source
    Description
    URL
    Notes
    -
    - - - Admin - - - - - - - - - - - - - -
    Results fetched:
    - - -
    - - - - -
    Results fetched:
    - - -
    - - - - -
    Results fetched:
    - - -
    - - -

    Set

    - - - - -
    setName
    -
    - - - - - - -

    This is a list of metadata formats available for the record "". Use these links to view the metadata:

    -
    - -

    This is a list of metadata formats available from this archive.

    -
    -
    - -
    - - -

    Metadata Format

    - - - - - - - -
    metadataPrefix
    metadataNamespace
    schema
    -
    - - - - - - - - -

    OAI Record:

    -
    - - - -
    -
    - - -

    OAI Record Header

    - - - - - - -
    OAI Identifier - - oai_dc - formats -
    Datestamp
    - -

    This record has been deleted.

    -
    -
    - - - -

    "about" part of record container not supported by the XSL

    -
    - - -   - - - - - - - - - - setSpec - - Identifiers - Records - - - - - - - - -

    There are more results.

    - - - -
    resumptionToken: - -Resume
    -
    - - - - -

    Unknown Metadata Format

    -
    - -
    -
    - - - - -
    -

    Dublin Core Metadata (oai_dc)

    - - -
    -
    -
    - - -Title - - -Author or Creator - - -Subject and Keywords - - -Description - - -Publisher - - -Other Contributor - - -Date - - -Resource Type - - -Format - - -Resource Identifier - - -Source - - -Language - - -Relation - - - - - URL - URL not shown as it is very long. - - - - - - - - - - - - - -Coverage - - -Rights Management - - - - -
    - <></> -
    -
    - - - - - ="" - - - -.xmlSource { - font-size: 70%; - border: solid #c0c0a0 1px; - background-color: #ffffe0; - padding: 2em 2em 2em 0em; -} -.xmlBlock { - padding-left: 2em; -} -.xmlTagName { - color: #800000; - font-weight: bold; -} -.xmlAttrName { - font-weight: bold; -} -.xmlAttrValue { - color: #0000c0; -} - - -
    - diff --git a/dspace-oai/dspace-oai-webapp/src/main/webapp/oai2.xsl.LICENSE b/dspace-oai/dspace-oai-webapp/src/main/webapp/oai2.xsl.LICENSE deleted file mode 100644 index d159169d10..0000000000 --- a/dspace-oai/dspace-oai-webapp/src/main/webapp/oai2.xsl.LICENSE +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/dspace-oai/dspace-oai-webapp/src/main/webapp/static/lyncode.png b/dspace-oai/dspace-oai-webapp/src/main/webapp/static/lyncode.png new file mode 100644 index 0000000000000000000000000000000000000000..dd372049fd1ae08d23a2ccc7f669da60ea025132 GIT binary patch literal 3749 zcmZWrXHb(1u>CNY&_Q~aCQVA{(nCV;B?t&=s6i1aq6i2k^x~xm(nAsHRjQ$e-h-gj zASguy1e78uLLT?eoj33O*ga==&+N?Z%+73_rMUq;4L1z{0Q5$Ny4Cke$m305lf&5C}_4PoDsvN1i^u0!9dgfUm!g$Gr#c0Pu7H zXM;xCY_e+}FCD^7VlinZKGtkh0@m;Z3~P$0q#!kuajanBJeyVb6+Jylo}q$RP+}tH z1)G%=T|CVkWKHmOVnk7F{K)B-kRq>{_T#VP=S{O(8&wCmh6xCPiZ0zy!Ac23R}SaD z@;PF#Z{W+C3=B&n;tMcQHMj{rIuoV$YnV19FE*7`uYng))x$bcN&7+U>}2@GiAEgPS(TkH zIcLLUdV;dJ z9i2z)LeJ4XcL{c94}OPf{5?MU+_@rxmA{QOpgj59Gj?cN%scUtI?`qFYm&j=7FzOO zz7IluMlN`JN!C>>X1_$;>=y^}#X@oLmlFNgrpRt9%TlKxtz{*k?!Fd9NQ!jXZCB7Q z6EPK0PMH|# zbvLU(ZE;7g6K?}4nX!5VYGukmxPUXij-kD&z4@GBnE3nVRgaiZYMDu+ zXzP{VeVi`xaxwOXQo=LLNi4EVA+d-)6%pn*guEC&`I6DwH^?dGDgCL3*20@o)VuS8$*NXjD1D@rPsDrjvFY)6qv<#%jCYxHduY*x#uKc-jOR^TkR zZFp?Z%iW!P~p5?E?a|u3QaIr3Ag`E2AG{mHI^A zj?X`PBH5OC#@CjhSy5i7icm0CuxqeBNb}H!tY-S19E8O$vF=H%Nbr;> zn&Rc$oxCd2Gt%uV4J)lG4YoU!Yj#R;B^`Qg4yRZKok3$UCouzb67e!_!)D&*Qz=a; zyP2liQH@N6S20gvn{Hs&!_wW%yv{qAJX4?2rJ#xIeujJ>W!6!RN`e}u@-3vn$JHK+y_!60dpVTOt*8fMJ@x{FXr&Weka+Qq5(}@7#^* z*KU^8SQjJl=jP;75|>vn^FHLm*FOj~tZ>6KEvd8&D3-VD08?q~CGb9oC_-TEAu zRMYI;9O{gA;Xt?a*YxhDcBF>3hW>M=389afXQ<@6#TWLd(VtcArrJ_AF?UxxwEr-D zQxnfXKS3O(TQXE)u?7YXJ^-Ie?e^qN$LuE;R$>Hvp3ZZ4FWz?eAC+}|5GUB-~*^L}b zo&-uU*C^1SIIIrV@zUu@@H4@#L~S*a`>*=>9i0~icpWyKr10wS_3mmx&!O+h)q=+x znZy+0J%%XDux~T(Ad*ThCbY=%zk&>VH6&MEc95oNhL?Op-V&dcgw&(m?L4~1<3?1| zEAy_8?~FB!kdjq$_wva*%stFsUN#p;o7hS7*?;Y*y02QV;TJ@rS!KI?J^CiNO5cKhZcIEw;G$ z8defV2HW#F@x`a>JTX2aU0I81jpdbnc()0UDUZ#sOVW9c4CxgaUo#jU($6n6(l6g^ z+&TKCN0QAL7bmqvG$ZguT^jG&-Ajjw8IYetIfUrb_PLHpfiXtL-Q>D<22ut zCek`-=K8h)!{F798Z{Cp&p&I!{&eQ^!HD&vF0p(K7p|Fn_T# z;%M7^pxAD8yG8rmL)ebaJmOQ#w6^2<;@sZi^ZSIrf`iFLgJW=1#Kd{ZQ4%BKa#B{( zXf%EFcHRvwRn--3|Fg}%rHBc)3DG=`^VjF2H5}}+VJFkuv&6~F$-<2NjMOggXT@h* zgl(=`(m>Auf9LR11-UziH&1uE0~Z7N_KKDnE!Lh1JQpW>{(gI8^S<;nl`A!sObN<7 z`0J`5O}h9u1zZiS%>W?y8USD-0N^+I0yhERF%$r{PynEo2>={EFYos2Uucn*rbxXD zB$LU)R|SCj_y5QL7yd{7x8}d(|0j*%?=mj>atBzO+W-KQfB+NQ8t$z*MnI73R0WW|BGN59U} z;hJN;-ZIH8WT7*?E~AR6Xswxz1qji_n)FksC_COwPY+#l+gnV0s&tz6v9<4aS8hv_ zPMKgxYliZ({;gRpShlm1u~jax7hc2NY@U=-6|SC$Ii%&R6Xc49&%lePt~4-%Icp-I zOz&?Hf8yoAt8@IXu-wi{gmj(O3OKl^=9k-#jR4!O5rQz(*q7*zwxZ(4?yTV} zEx}Q~?x;19P?8tovfO)l%Z4kUa=`e0$R zAI&&#v_0^Q2p9mT-c(ie{xQ2C&6Dn4_s#xlA~u>4*0OaC5M2@+ON{Ga0>Mj*QI!#L zpFfKPQ;q(-$&Lr{Qg#lY?ilW)=+vH4b?Ws&V!*9%X(o`tB5#7uWxD$h{lyw*8(&K7 zvQF88cNr=e`wIq~crn9GUXW&`O*9Iuc$9XB2wQn%LU_DL_(%B*NFnpdoUb@ojf=U0 znuA&IO^F~~Ns+KKD!lHkgTmvP;rWdtZ*WB}cKnhgijW!wc{k#32mV%#F>TW4-nIrS z;`N_1gK(|{6RzZ|;{~Kh3U&U7qFjjc;?N_mT2*OI=+Ir3(?wcIza}Oyb0^2h-oOr* z8+}`^HnjM>`$yUHI?agOe8b;*dSODO35&%%9nm|PUuQfb!l87ikUm{EG2Y(qQCnt3g|$GI|sunVB&Sg7E-vR$ZcM^f}X{EyC>^d zhc0GtM6ZVj5ejERVX9jGBeQ zW3+zas6f#3f*jM&Or6@$*Fx9mc7vWnOC}6g28Hu=SbTk?&R2!W<^6?w%Y~nlO#TY) qEfwZY$h+Yq_bk&`>Bh%le;_Z+tepqP6K-AH9$=(ru3G~~h5ru~=+`>{ literal 0 HcmV?d00001 diff --git a/dspace-oai/dspace-oai-webapp/src/main/webapp/static/style.xsl b/dspace-oai/dspace-oai-webapp/src/main/webapp/static/style.xsl new file mode 100644 index 0000000000..c9de302a62 --- /dev/null +++ b/dspace-oai/dspace-oai-webapp/src/main/webapp/static/style.xsl @@ -0,0 +1,1150 @@ + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> + + + + + + + + DSpace OAI-PMH Data Provider + + + + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Repository Name
    E-Mail Contact + + + + +
    Description
    Protocol Version
    Earliest Registered Date
    Date Granularity
    Deletion Mode
    +
    + +
    + + + + + +
    +
    + +
    + + setalternate + +
    + + + ... + + + + + + () +
    + +
    +
    +
    +
    + + + + +
    + +
    + +
    +
    + +
    +
    +
    + +
    + +
    + +
    +
    + + + + + +
    + +
    + + identifieralternate + +
    + + + + +
    +
    + + + + +
    +
    + Sets +
    + +
    + + + setspecalternate + + + + +
    +
    +
    +
    + + + + + Get Record + +
    +
    +
    +
    + + + + +
    + +
    + +
    +
    +
    + + +
    +
    + + +
    +
    +
    + +
    + + +
    + + recSetAlternate + + + +
    +
    +
    +
    +
    +
    +
    + +
    +
    + +
    + +
    + + + + + + +
    + +
    + + + getRecordAlternate multiple + + +
    +
    + + +
    +
    + + +
    +
    +
    + +
    + +
    + + recSetAlternate + + + +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    + + + + + +
    +
    + +
    + + +
    + + + + + + +
    +
    + + level + + <> + +
    + + level + + </> +
    +
    + + +
    +
    + level divText + +
    +
    + + +
    ="
    " +
    + + + + + + + + + + + - + + + - + + + + + + + + + of + + +
    diff --git a/dspace-oai/pom.xml b/dspace-oai/pom.xml index a6c32dfb24..e6234b9231 100644 --- a/dspace-oai/pom.xml +++ b/dspace-oai/pom.xml @@ -1,24 +1,35 @@ - - 4.0.0 - org.dspace - dspace-oai - pom - DSpace OAI - Parent for DSpace OAI Service Provider Webapplication + + + 4.0.0 + + dspace-parent + org.dspace + 3.0-SNAPSHOT + + dspace-oai + pom - - - org.dspace - dspace-parent - 3.0-SNAPSHOT - .. - - - - dspace-oai-api - dspace-oai-webapp - - \ No newline at end of file + + DSpace OAI 2.0 + Parent project for the OAI API and Webapp + http://www.lyncode.com/dspace/addons/xoai + + dspace-oai-api + dspace-oai-webapp + + + + + + DSpace @ Lyncode + dspace@lyncode.com + Lyncode + http://www.lyncode.com + + + helix84 + Ivan Másar + helix84@centrum.sk + + + diff --git a/dspace/config/default.context.xml b/dspace/config/default.context.xml index 1e16051669..68e3e1342a 100644 --- a/dspace/config/default.context.xml +++ b/dspace/config/default.context.xml @@ -4,7 +4,4 @@ - - \ No newline at end of file + diff --git a/dspace/config/launcher.xml b/dspace/config/launcher.xml index 938ef83d11..06283fd17f 100644 --- a/dspace/config/launcher.xml +++ b/dspace/config/launcher.xml @@ -356,12 +356,12 @@ - update-discovery-index - Update Discovery Solr Search Index - - org.dspace.discovery.IndexClient - - + update-discovery-index + Update Discovery Solr Search Index + + org.dspace.discovery.IndexClient + + migrate-embargo @@ -371,6 +371,12 @@ - + + oai + OAI script manager + + org.dspace.xoai.app.XOAI + + diff --git a/dspace/config/modules/oai.cfg b/dspace/config/modules/oai.cfg index 9b9adf1ed6..705f5af398 100644 --- a/dspace/config/modules/oai.cfg +++ b/dspace/config/modules/oai.cfg @@ -1,108 +1,25 @@ #---------------------------------------------------------------# -#-------------OAI-PMH & OAI-ORE CONFIGURATIONS------------------# +#--------------------XOAI CONFIGURATIONS------------------------# #---------------------------------------------------------------# -# These configs are used by both OAI-PMH and OAI-ORE # -# (Harvester) Interfaces. # -#---------------------------------------------------------------# -# The base URL of the OAI webapp (do not include /request). -dspace.oai.url = ${dspace.baseUrl}/oai - - -#---------------------------------------------------------------# -#--------------OAI-PMH SPECIFIC CONFIGURATIONS------------------# -#---------------------------------------------------------------# -# These configs are only used by the OAI-PMH interface # +# These configs are used by the XOAI # #---------------------------------------------------------------# -# Max response size for DIDL. This is the maximum size in bytes of the files you -# wish to enclose Base64 encoded in your responses, remember that the base64 -# encoding process uses a lot of memory. We recommend at most 200000 for answers -# of 30 records each on a 1 Gigabyte machine. Ultimately, this will change to a -# streaming model and remove this restriction. Also please remember to allocate -# plenty of memory, at least 512 MB to your Tomcat. -# -# didl.maxresponse = 0 +# Storage: solr | database +storage=solr -# DSpace by default uses 100 records as the limit for the oai responses. -# This can be altered by enabling the oai.response.max-records parameter -# and setting the desired amount of results. -response.max-records = 100 +# Base solr index +solr.url=${solr.server}/oai +# OAI persistent identifier prefix. +# Format - oai:PREFIX:HANDLE +identifier.prefix = ${dspace.hostname} +# Base url for bitstreams +bitstream.baseUrl = ${dspace.url} +# Base Configuration Directory +config.dir = ${dspace.dir}/config/modules/oai -#---------------------------------------------------------------# -#--------------OAI HARVESTING CONFIGURATIONS--------------------# -#---------------------------------------------------------------# -# These configs are only used by the OAI-ORE related functions # -#---------------------------------------------------------------# +# Cache enabled? +cache.enabled = true -### Harvester settings - -# Crosswalk settings; the {name} value must correspond to a declared ingestion crosswalk -# harvester.oai.metadataformats.{name} = {namespace},{optional display name} -# The display name is only used in the xmlui for the jspui there are entries in the -# Messages.properties in the form jsp.tools.edit-collection.form.label21.select.{name} -harvester.oai.metadataformats.dc = http://www.openarchives.org/OAI/2.0/oai_dc/, Simple Dublin Core -harvester.oai.metadataformats.qdc = http://purl.org/dc/terms/, Qualified Dublin Core -harvester.oai.metadataformats.dim = http://www.dspace.org/xmlns/dspace/dim, DSpace Intermediate Metadata - -# This field works in much the same way as harvester.oai.metadataformats.PluginName -# The {name} must correspond to a declared ingestion crosswalk, while the -# {namespace} must be supported by the target OAI-PMH provider when harvesting content. -# harvester.oai.oreSerializationFormat.{name} = {namespace} - -# Determines whether the harvester scheduling process should be started -# automatically when the DSpace webapp is deployed. -# default: false -harvester.autoStart=false - -# Amount of time subtracted from the from argument of the PMH request to account -# for the time taken to negotiate a connection. Measured in seconds. Default value is 120. -#harvester.timePadding = 120 - -# How frequently the harvest scheduler checks the remote provider for updates, -# measured in minutes. The default value is 12 hours (or 720 minutes) -#harvester.harvestFrequency = 720 - -# The heartbeat is the frequency at which the harvest scheduler queries the local -# database to determine if any collections are due for a harvest cycle (based on -# the harvestFrequency) value. The scheduler is optimized to then sleep until the -# next collection is actually ready to be harvested. The minHeartbeat and -# maxHeartbeat are the lower and upper bounds on this timeframe. Measured in seconds. -# Default minHeartbeat is 30. Default maxHeartbeat is 3600. -#harvester.minHeartbeat = 30 -#harvester.maxHeartbeat = 3600 - -# How many harvest process threads the scheduler can spool up at once. Default value is 3. -#harvester.maxThreads = 3 - -# How much time passess before a harvest thread is terminated. The termination process -# waits for the current item to complete ingest and saves progress made up to that point. -# Measured in hours. Default value is 24. -#harvester.threadTimeout = 24 - -# When harvesting an item that contains an unknown schema or field within a schema what -# should the harvester do? Either add a new registry item for the field or schema, ignore -# the specific field or schema (importing everything else about the item), or fail with -# an error. The default value if undefined is: fail. -# Possible values: 'fail', 'add', or 'ignore' -harvester.unknownField = add -harvester.unknownSchema = fail - -# The webapp responsible for minting the URIs for ORE Resource Maps. -# If using oai, the dspace.oai.uri config value must be set. -# The URIs generated for ORE ReMs follow the following convention for both cases. -# format: [baseURI]/metadata/handle/[theHandle]/ore.xml -# Default value is oai -#ore.authoritative.source = oai - -# A harvest process will attempt to scan the metadata of the incoming items -# (dc.identifier.uri field, to be exact) to see if it looks like a handle. -# If so, it matches the pattern against the values of this parameter. -# If there is a match the new item is assigned the handle from the metadata value -# instead of minting a new one. Default value: hdl.handle.net -#harvester.acceptedHandleServer = hdl.handle.net, handle.myu.edu - -# Pattern to reject as an invalid handle prefix (known test string, for example) -# when attempting to find the handle of harvested items. If there is a match with -# this config parameter, a new handle will be minted instead. Default value: 123456789. -#harvester.rejectedHandlePrefix = 123456789, myTestHandle +# Base Cache Directory +cache.dir = ${dspace.dir}/var/oai diff --git a/dspace/config/modules/oai/metadataFormats/didl.xsl b/dspace/config/modules/oai/metadataFormats/didl.xsl new file mode 100644 index 0000000000..a25a663081 --- /dev/null +++ b/dspace/config/modules/oai/metadataFormats/didl.xsl @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + urn:hdl: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + / + + + + + + + + + + + + + + + + + diff --git a/dspace/config/modules/oai/metadataFormats/dim.xsl b/dspace/config/modules/oai/metadataFormats/dim.xsl new file mode 100644 index 0000000000..64a963e85d --- /dev/null +++ b/dspace/config/modules/oai/metadataFormats/dim.xsl @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace/config/modules/oai/metadataFormats/etdms.xsl b/dspace/config/modules/oai/metadataFormats/etdms.xsl new file mode 100644 index 0000000000..ffd0251eb6 --- /dev/null +++ b/dspace/config/modules/oai/metadataFormats/etdms.xsl @@ -0,0 +1,116 @@ + + + + + + + + + <xsl:value-of select="." /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace/config/modules/oai/metadataFormats/marc.xsl b/dspace/config/modules/oai/metadataFormats/marc.xsl new file mode 100644 index 0000000000..8ae77da381 --- /dev/null +++ b/dspace/config/modules/oai/metadataFormats/marc.xsl @@ -0,0 +1,63 @@ + + + + + + + + am 3u + + dc + + + + + author + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace/config/modules/oai/metadataFormats/mets.xsl b/dspace/config/modules/oai/metadataFormats/mets.xsl new file mode 100644 index 0000000000..226ccedd24 --- /dev/null +++ b/dspace/config/modules/oai/metadataFormats/mets.xsl @@ -0,0 +1,303 @@ + + + + + + + + + + hdl: + + + DSpace_ITEM_ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + URL + + + File + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + URL + + + File + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + +
    + + + + + +
    +
    +
    +
    +
    +
    +
    + +
    diff --git a/dspace/config/modules/oai/metadataFormats/mods.xsl b/dspace/config/modules/oai/metadataFormats/mods.xsl new file mode 100644 index 0000000000..7f6cafce1d --- /dev/null +++ b/dspace/config/modules/oai/metadataFormats/mods.xsl @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace/config/modules/oai/metadataFormats/oai_dc.xsl b/dspace/config/modules/oai/metadataFormats/oai_dc.xsl new file mode 100644 index 0000000000..40ea796f96 --- /dev/null +++ b/dspace/config/modules/oai/metadataFormats/oai_dc.xsl @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace/config/modules/oai/metadataFormats/ore.xsl b/dspace/config/modules/oai/metadataFormats/ore.xsl new file mode 100644 index 0000000000..8b206b4558 --- /dev/null +++ b/dspace/config/modules/oai/metadataFormats/ore.xsl @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace/config/modules/oai/metadataFormats/qdc.xsl b/dspace/config/modules/oai/metadataFormats/qdc.xsl new file mode 100644 index 0000000000..5e9c2ae486 --- /dev/null +++ b/dspace/config/modules/oai/metadataFormats/qdc.xsl @@ -0,0 +1,345 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace/config/modules/oai/metadataFormats/rdf.xsl b/dspace/config/modules/oai/metadataFormats/rdf.xsl new file mode 100644 index 0000000000..8b652625c7 --- /dev/null +++ b/dspace/config/modules/oai/metadataFormats/rdf.xsl @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace/config/modules/oai/metadataFormats/uketd_dc.xsl b/dspace/config/modules/oai/metadataFormats/uketd_dc.xsl new file mode 100644 index 0000000000..c7a1aa010d --- /dev/null +++ b/dspace/config/modules/oai/metadataFormats/uketd_dc.xsl @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace/config/modules/oai/metadataFormats/xoai.xsl b/dspace/config/modules/oai/metadataFormats/xoai.xsl new file mode 100644 index 0000000000..d9d28e96ff --- /dev/null +++ b/dspace/config/modules/oai/metadataFormats/xoai.xsl @@ -0,0 +1,25 @@ + + + + + + + + + + + diff --git a/dspace/config/modules/oai/transformers/driver.xsl b/dspace/config/modules/oai/transformers/driver.xsl new file mode 100644 index 0000000000..6b53702268 --- /dev/null +++ b/dspace/config/modules/oai/transformers/driver.xsl @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + info:eu-repo/semantics/openAccess + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace/config/modules/oai/transformers/openaire.xsl b/dspace/config/modules/oai/transformers/openaire.xsl new file mode 100644 index 0000000000..8897e00170 --- /dev/null +++ b/dspace/config/modules/oai/transformers/openaire.xsl @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + info:eu-repo/semantics/openAccess + + + info:eu-repo/semantics/openAccess + + + info:eu-repo/semantics/restrictedAccess + + + info:eu-repo/semantics/embargoedAccess + + + info:eu-repo/semantics/restrictedAccess + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace/config/modules/oai/xoai.xml b/dspace/config/modules/oai/xoai.xml new file mode 100644 index 0000000000..f9123cc0fe --- /dev/null +++ b/dspace/config/modules/oai/xoai.xml @@ -0,0 +1,259 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + oai_dc + metadataFormats/oai_dc.xsl + http://www.openarchives.org/OAI/2.0/oai_dc/ + http://www.openarchives.org/OAI/2.0/oai_dc.xsd + + + mets + metadataFormats/mets.xsl + http://www.loc.gov/METS/ + http://www.loc.gov/standards/mets/mets.xsd + + + + xoai + metadataFormats/xoai.xsl + http://www.lyncode.com/xoai + http://www.lyncode.com/schemas/xoai.xsd + + + didl + metadataFormats/didl.xsl + urn:mpeg:mpeg21:2002:02-DIDL-NS + http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-21_schema_files/did/didl.xsd + + + dim + metadataFormats/dim.xsl + http://www.dspace.org/xmlns/dspace/dim + http://www.dspace.org/schema/dim.xsd + + + ore + metadataFormats/ore.xsl + http://www.w3.org/2005/Atom + http://tweety.lanl.gov/public/schemas/2008-06/atom-tron.sch + + + rdf + metadataFormats/rdf.xsl + http://www.openarchives.org/OAI/2.0/rdf/ + http://www.openarchives.org/OAI/2.0/rdf.xsd + + + etdms + metadataFormats/etdms.xsl + http://www.ndltd.org/standards/metadata/etdms/1.0/ + http://www.ndltd.org/standards/metadata/etdms/1.0/etdms.xsd + + + mods + metadataFormats/mods.xsl + http://www.loc.gov/mods/v3 + http://www.loc.gov/standards/mods/v3/mods-3-1.xsd + + + qdc + metadataFormats/qdc.xsl + http://purl.org/dc/terms/ + http://dublincore.org/schemas/xmls/qdc/2006/01/06/dcterms.xsd + + + marc + metadataFormats/marc.xsl + http://www.loc.gov/MARC21/slim + http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd + + + uketd_dc + metadataFormats/uketd_dc.xsl + http://naca.central.cranfield.ac.uk/ethos-oai/2.0/ + http://naca.central.cranfield.ac.uk/ethos-oai/2.0/uketd_dc.xsd + + + + + + transformers/driver.xsl + + + transformers/openaire.xsl + + + + + + + org.dspace.xoai.filter.DSpaceMetadataExistsFilter + + dc.contributor.author + + + + + org.dspace.xoai.filter.DSpaceMetadataExistsFilter + + dc.title + + + + + org.dspace.xoai.filter.DSpaceAtLeastOneMetadataFilter + + dc.type + + + ends_with + + + article + bachelorThesis + masterThesis + doctoralThesis + book + bookPart + review + conferenceObject + lecture + workingPaper + preprint + report + annotation + contributionToPeriodical + patent + other + + + + org.dspace.xoai.filter.DSpaceAtLeastOneMetadataFilter + + dc.rights + + + contains + + + open access + openAccess + + + + org.dspace.xoai.filter.DSpaceAuthorizationFilter + + + org.dspace.xoai.filter.DSpaceAtLeastOneMetadataFilter + + dc.relation + + + starts_with + + + info:eurepo/grantAgreement/EC/FP + + + + + + + driver + Open Access DRIVERset + + + + ec_fundedresources + EC_fundedresources set + + + + diff --git a/dspace/config/oaicat.properties b/dspace/config/oaicat.properties deleted file mode 100644 index 70b986f6d6..0000000000 --- a/dspace/config/oaicat.properties +++ /dev/null @@ -1,52 +0,0 @@ -########################################################################### -# REMEMBER: ONLY UPDATE THE VERSION IN dspace/config/templates -# AND THEN RUN dspace/bin/install-configs! -# DO NOT EDIT THE 'LIVE' VERSION! -########################################################################### - -# OAICat Configuration file - see OAICat documentation for details - -# Text surrounded by two '${' and '}' symbols is replaced with the corresponding -# property from dspace.cfg. For example: -# -# ${dspace.url} -# -# would be replaced with the dspace.url property in dspace.cfg on Maven compilation - -AbstractCatalog.oaiCatalogClassName=org.dspace.app.oai.DSpaceOAICatalog -AbstractCatalog.recordFactoryClassName=org.dspace.app.oai.DSpaceRecordFactory -AbstractCatalog.secondsToLive=3600 - -AbstractCatalog.granularity=YYYY-MM-DDThh:mm:ssZ - -# Custom Identify response values -Identify.repositoryName=${dspace.name} -Identify.adminEmail=${mail.admin} -Identify.earliestDatestamp=2001-01-01T00:00:00Z -Identify.deletedRecord=persistent - -# List the supported metadataPrefixes along with the class that performs the associated crosswalk -#Crosswalks.didl=org.dspace.app.oai.DIDLCrosswalk -Crosswalks.mets=org.dspace.app.oai.METSCrosswalk -Crosswalks.oai_dc=org.dspace.app.oai.OAIDCCrosswalk -Crosswalks.rdf=org.dspace.app.oai.RDFCrosswalk -#Crosswalks.uketd_dc=org.dspace.app.oai.UKETDDCCrosswalk - -# The following OAI crosswalks use crosswalk plugins defined in dspace.cfg. -# The metadataPrefixes must match the name of the plugin -# for interface org.dspace.content.crosswalk.DisseminationCrosswalk -# (e.g. "ore" matches the DisseminationCrosswalk of that name in dspace.cfg) -Crosswalks.ore=org.dspace.app.oai.PluginCrosswalk -# Uncomment any of the below plugins to enable other harvestable metadata -# formats. Remember to also check the corresponding DisseminationCrosswalk -# settings in your dspace.cfg file. -# Crosswalks.mods=org.dspace.app.oai.PluginCrosswalk -# Crosswalks.mets=org.dspace.app.oai.PluginCrosswalk -# Crosswalks.qdc=org.dspace.app.oai.PluginCrosswalk -# Crosswalks.dim=org.dspace.app.oai.PluginCrosswalk -# Crosswalks.marc=org.dspace.app.oai.PluginCrosswalk - -# XSLT stylesheet to transform OAI-PMH XML results in web browser to -# human-readable and browsable HTML pages -OAIHandler.styleSheet=/oai/oai2.xsl - diff --git a/dspace/modules/oai/pom.xml b/dspace/modules/oai/pom.xml index 7a14b320a5..81de92971c 100644 --- a/dspace/modules/oai/pom.xml +++ b/dspace/modules/oai/pom.xml @@ -1,101 +1,131 @@ - - 4.0.0 - org.dspace.modules - oai - war - DSpace OAI :: Web Application - - DSpace OAI Service Provider Web Application - + + + 4.0.0 + + modules + org.dspace + 3.0-SNAPSHOT + .. + + org.dspace.modules + oai + war + DSpace OAI 2.0 :: Web Application + http://www.lyncode.com + XOAI Interface - - - org.dspace - modules - 3.0-SNAPSHOT - .. - + + + + org.apache.maven.plugins + maven-war-plugin + + false + + + true + ${basedir}/src/main/webapp + + WEB-INF/web.xml + + + + + + + prepare-package + + + + + - - - - org.apache.maven.plugins - maven-war-plugin - - false - - - true - ${basedir}/src/main/webapp - - WEB-INF/web.xml - - - - - - - prepare-package - - - - - + + + + + dspace.config + + + + + ${dspace.config} + + + + + oracle-support + + + db.name + oracle + + + + + com.oracle + ojdbc6 + + + + + postgres-support + + + !db.name + + + + + postgresql + postgresql + + + + + + + + org.dspace + dspace-oai-webapp + war + + + org.dspace + dspace-oai-api + 3.0-SNAPSHOT + + + javax.servlet + servlet-api + provided + + + org.slf4j + slf4j-log4j12 + 1.5.6 + + + org.apache.solr + solr-core + 3.3.0 + + + org.slf4j + slf4j-jdk14 + 1.5.6 + + - - - postgres-support - - - !db.name - - - - - postgresql - postgresql - - - - - oracle-support - - - db.name - oracle - - - - - com.oracle - ojdbc6 - - - - + + + lyncode + dspace@lyncode.com + DSpace @ Lyncode + http://www.lyncode.com + + + - - - org.dspace.modules - additions - - - org.dspace - dspace-oai-webapp - war - - - org.dspace - dspace-oai-api - - - javax.servlet - servlet-api - provided - - - - \ No newline at end of file diff --git a/dspace/modules/pom.xml b/dspace/modules/pom.xml index fe9596e1e8..e6d2e24879 100644 --- a/dspace/modules/pom.xml +++ b/dspace/modules/pom.xml @@ -52,15 +52,6 @@ lni - - dspace-oai - - true - - - oai - - dspace-jspui @@ -97,5 +88,14 @@ solr + + dspace-xoai + + true + + + oai + +
    diff --git a/dspace/pom.xml b/dspace/pom.xml index d7b118053d..b121d2eea4 100644 --- a/dspace/pom.xml +++ b/dspace/pom.xml @@ -84,5 +84,16 @@ - + + + + org.dspace + dspace-oai-api + + + javax.servlet + servlet-api + 2.3 + + diff --git a/dspace/solr/oai/conf/admin-extra.html b/dspace/solr/oai/conf/admin-extra.html new file mode 100644 index 0000000000..aa739da862 --- /dev/null +++ b/dspace/solr/oai/conf/admin-extra.html @@ -0,0 +1,31 @@ + + + diff --git a/dspace/solr/oai/conf/elevate.xml b/dspace/solr/oai/conf/elevate.xml new file mode 100644 index 0000000000..7630ebe20f --- /dev/null +++ b/dspace/solr/oai/conf/elevate.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + diff --git a/dspace/solr/oai/conf/protwords.txt b/dspace/solr/oai/conf/protwords.txt new file mode 100644 index 0000000000..1dfc0abecb --- /dev/null +++ b/dspace/solr/oai/conf/protwords.txt @@ -0,0 +1,21 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#----------------------------------------------------------------------- +# Use a protected word file to protect against the stemmer reducing two +# unrelated words to the same base word. + +# Some non-words that normally won't be encountered, +# just to test that they won't be stemmed. +dontstems +zwhacky + diff --git a/dspace/solr/oai/conf/schema.xml b/dspace/solr/oai/conf/schema.xml new file mode 100644 index 0000000000..67780813e3 --- /dev/null +++ b/dspace/solr/oai/conf/schema.xml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + item.handle + item.handle + + diff --git a/dspace/solr/oai/conf/solrconfig.xml b/dspace/solr/oai/conf/solrconfig.xml new file mode 100644 index 0000000000..2ccd3410cc --- /dev/null +++ b/dspace/solr/oai/conf/solrconfig.xml @@ -0,0 +1,1037 @@ + + + + + + ${solr.abortOnConfigurationError:true} + + + + + + + + + + + + + + + + + + + + + + false + + 10 + + + + + 32 + + 10000 + 1000 + 10000 + + + + + + + + + + + + + native + + + + + + + false + 32 + 10 + + + + + + + + false + + + true + + + + + + + + 1 + + 0 + + + + + false + + + + + + + + + + + + + 10000 + 10000 + + + + + + + + + + + + + + + + + 1024 + + + + + + + + + + + + + + + + true + + + + + + + + 20 + + + 200 + + + + + + + + + + + + + solr rocks010 + static firstSearcher warming query from solrconfig.xml + + + + + false + + + 2 + + + + + + + + + + + + + + + + + + + + + + + explicit + + + + + + + + + + + + + dismax + explicit + 0.01 + + text^0.5 features^1.0 name^1.2 sku^1.5 id^10.0 manu^1.1 cat^1.4 + + + text^0.2 features^1.1 name^1.5 manu^1.4 manu_exact^1.9 + + + popularity^0.5 recip(price,1,1000,1000)^0.3 + + + id,name,price,score + + + 2<-1 5<-2 6<90% + + 100 + *:* + + text features name + + 0 + + name + regex + + + + + + + dismax + explicit + text^0.5 features^1.0 name^1.2 sku^1.5 id^10.0 + 2<-1 5<-2 6<90% + + incubationdate_dt:[* TO NOW/DAY-1MONTH]^2.2 + + + + inStock:true + + + + cat + manu_exact + price:[* TO 500] + price:[500 TO *] + + + + + + + + + + textSpell + + + default + name + ./spellchecker + + + + + + + + + + + + false + + false + + 1 + + + spellcheck + + + + + + + + true + + + tvComponent + + + + + + + + + default + + org.carrot2.clustering.lingo.LingoClusteringAlgorithm + + 20 + + + stc + org.carrot2.clustering.stc.STCClusteringAlgorithm + + + + + true + default + true + + name + id + + features + + true + + + + false + + + clusteringComponent + + + + + + + + text + true + ignored_ + + + true + links + ignored_ + + + + + + + + + + true + + + termsComponent + + + + + + + + string + elevate.xml + + + + + + explicit + + + elevator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + standard + solrpingquery + all + + + + + + + explicit + true + + + + + + + + + 100 + + + + + + + + 70 + + 0.5 + + [-\w ,/\n\"']{20,200} + + + + + + + ]]> + ]]> + + + + + + + + + + + + + 5 + + + + + + + + + + solr + + + + + diff --git a/dspace/solr/oai/conf/spellings.txt b/dspace/solr/oai/conf/spellings.txt new file mode 100644 index 0000000000..162a044d56 --- /dev/null +++ b/dspace/solr/oai/conf/spellings.txt @@ -0,0 +1,2 @@ +pizza +history diff --git a/dspace/solr/oai/conf/stopwords.txt b/dspace/solr/oai/conf/stopwords.txt new file mode 100644 index 0000000000..8433c832d2 --- /dev/null +++ b/dspace/solr/oai/conf/stopwords.txt @@ -0,0 +1,57 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#----------------------------------------------------------------------- +# a couple of test stopwords to test that the words are really being +# configured from this file: +stopworda +stopwordb + +#Standard english stop words taken from Lucene's StopAnalyzer +an +and +are +as +at +be +but +by +for +if +in +into +is +it +no +not +of +on +or +s +such +t +that +the +their +then +there +these +they +this +to +was +will +with + diff --git a/dspace/solr/oai/conf/synonyms.txt b/dspace/solr/oai/conf/synonyms.txt new file mode 100644 index 0000000000..b0e31cb7ec --- /dev/null +++ b/dspace/solr/oai/conf/synonyms.txt @@ -0,0 +1,31 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#----------------------------------------------------------------------- +#some test synonym mappings unlikely to appear in real input text +aaa => aaaa +bbb => bbbb1 bbbb2 +ccc => cccc1,cccc2 +a\=>a => b\=>b +a\,a => b\,b +fooaaa,baraaa,bazaaa + +# Some synonym groups specific to this example +GB,gib,gigabyte,gigabytes +MB,mib,megabyte,megabytes +Television, Televisions, TV, TVs +#notice we use "gib" instead of "GiB" so any WordDelimiterFilter coming +#after us won't split it into two words. + +# Synonym mappings can be used for spelling correction too +pixima => pixma + diff --git a/dspace/solr/oai/conf/xslt/DRI.xsl b/dspace/solr/oai/conf/xslt/DRI.xsl new file mode 100644 index 0000000000..f68043c843 --- /dev/null +++ b/dspace/solr/oai/conf/xslt/DRI.xsl @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /metadata/handle/ + + /mets.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dspace/solr/oai/conf/xslt/example.xsl b/dspace/solr/oai/conf/xslt/example.xsl new file mode 100644 index 0000000000..6832a1d4cb --- /dev/null +++ b/dspace/solr/oai/conf/xslt/example.xsl @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + <xsl:value-of select="$title"/> + + + +

    +
    + This has been formatted by the sample "example.xsl" transform - + use your own XSLT to get a nicer page +
    + + + +
    + + + +
    + + + + +
    +
    +
    + + + + + + + + + + + + + + javascript:toggle("");? +
    + + exp + + + + + +
    + + +
    + + + + + + + +
      + +
    • +
      +
    + + +
    + + + + + + + + + + + + + + + + + + + + +
    diff --git a/dspace/solr/oai/conf/xslt/example_atom.xsl b/dspace/solr/oai/conf/xslt/example_atom.xsl new file mode 100644 index 0000000000..e1c7d5a2af --- /dev/null +++ b/dspace/solr/oai/conf/xslt/example_atom.xsl @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + Example Solr Atom 1.0 Feed + + This has been formatted by the sample "example_atom.xsl" transform - + use your own XSLT to get a nicer Atom feed. + + + Apache Solr + solr-user@lucene.apache.org + + + + + + tag:localhost,2007:example + + + + + + + + + <xsl:value-of select="str[@name='name']"/> + + tag:localhost,2007: + + + + + + diff --git a/dspace/solr/oai/conf/xslt/example_rss.xsl b/dspace/solr/oai/conf/xslt/example_rss.xsl new file mode 100644 index 0000000000..3e09e654d5 --- /dev/null +++ b/dspace/solr/oai/conf/xslt/example_rss.xsl @@ -0,0 +1,66 @@ + + + + + + + + + + + + + Example Solr RSS 2.0 Feed + http://localhost:8983/solr + + This has been formatted by the sample "example_rss.xsl" transform - + use your own XSLT to get a nicer RSS feed. + + en-us + http://localhost:8983/solr + + + + + + + + + + + <xsl:value-of select="str[@name='name']"/> + + http://localhost:8983/solr/select?q=id: + + + + + + + http://localhost:8983/solr/select?q=id: + + + + diff --git a/dspace/solr/oai/conf/xslt/luke.xsl b/dspace/solr/oai/conf/xslt/luke.xsl new file mode 100644 index 0000000000..6e9a064d7e --- /dev/null +++ b/dspace/solr/oai/conf/xslt/luke.xsl @@ -0,0 +1,337 @@ + + + + + + + + + Solr Luke Request Handler Response + + + + + + + + + <xsl:value-of select="$title"/> + + + + + +

    + +

    +
    + +
    + +

    Index Statistics

    + +
    + +

    Field Statistics

    + + + +

    Document statistics

    + + + + +
    + + + + + +
    + +
    + + +
    + +
    + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    +

    + +

    + +
    + +
    +
    +
    + + +
    + + 50 + 800 + 160 + blue + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + background-color: ; width: px; height: px; +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + +
    • + +
    • +
      +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + + + + + + + + + + + + + + + + +
    diff --git a/dspace/solr/solr.xml b/dspace/solr/solr.xml index 0d7c2cd772..df5fa54453 100644 --- a/dspace/solr/solr.xml +++ b/dspace/solr/solr.xml @@ -1,36 +1,37 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/dspace/src/main/config/build.xml b/dspace/src/main/config/build.xml index 3d2b51a9c7..eb5b53e50c 100644 --- a/dspace/src/main/config/build.xml +++ b/dspace/src/main/config/build.xml @@ -730,6 +730,10 @@ Common usage: + + + + diff --git a/pom.xml b/pom.xml index 0e56661261..48763b6a8f 100644 --- a/pom.xml +++ b/pom.xml @@ -236,7 +236,7 @@ dspace-oai @@ -641,11 +641,6 @@ mets 1.5.2 - - org.dspace - oaicat - 1.5.48 - org.dspace.dependencies dspace-tm-extractors @@ -1197,5 +1192,4 @@ -