diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..4e2971e9ea7d99331dfe46c7d52e17ae1fa2c436 --- /dev/null +++ b/LICENSE @@ -0,0 +1,40 @@ +DSpace source code license: + + +Copyright (c) 2002-2013, DuraSpace. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name DuraSpace nor the name of the DSpace Foundation +nor the names of its contributors may be used to endorse or promote +products derived from this software without specific prior written +permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + + +DSpace uses third-party libraries which may be distributed under +different licenses to the above. Information about these licenses +is detailed in the LICENSES_THIRD_PARTY file at the root of the source +tree. You must agree to the terms of these licenses, in addition to +the above DSpace source code license, in order to use this software. diff --git a/LICENSES_THIRD_PARTY b/LICENSES_THIRD_PARTY new file mode 100644 index 0000000000000000000000000000000000000000..011574ae3f9a485de7a53c675630ea4cef339dff --- /dev/null +++ b/LICENSES_THIRD_PARTY @@ -0,0 +1,163 @@ +DSpace uses third-party libraries which may be distributed under different +licenses. We have attempted to list all of these third party libraries and +their licenses below (however the most up-to-date information can be found +via Maven, see NOTE #2 at bottom of this page). + +You must agree to the terms of these licenses, in addition to the DSpace +source code license, in order to use this software. + +-------------------------------------------------- +Third party Java libraries listed by License type +[Format: Name (Maven Project) - URL] +-------------------------------------------------- + +Apache Software License, Version 2.0 (http://opensource.org/licenses/apache2.0) + * Ant-Contrib Tasks (ant-contrib:*) - http://ant-contrib.sourceforge.net/ + * Apache Abdera (org.apache.abdera::*) - http://projects.apache.org/projects/abdera.html + * Apache Ant (org.apache.ant:*) - http://ant.apache.org/ + * Apache Axis (axis:*) - http://axis.apache.org/axis/ + * Apache Cocoon (org.apache.cocoon:*) - http://cocoon.apache.org/2.2/license.html + * Apache Commons BeanUtils (commons-beanutils:*) - http://commons.apache.org/beanutils/ + * Apache Commons CLI (commons-cli:*) - http://commons.apache.org/cli/license.html + * Apache Commons Codec (commons-codec:*) - http://commons.apache.org/codec/license.html + * Apache Commons Collections (commons-collections:*) - http://commons.apache.org/collections/license.html + * Apache Commons Configuration (commons-configuration:*) - http://commons.apache.org/configuration/license.html + * Apache Commons DBCP (commons-dbcp:*) - http://commons.apache.org/dbcp/license.html + * Apache Commons Digester (commons-digester:*) - http://commons.apache.org/digester/ + * Apache Commons Discovery (commons-discovery:*) - http://commons.apache.org/discovery/license.html + * Apache Commons FileUpload (commons-fileupload:*) - http://commons.apache.org/fileupload/license.html + * Apache Commons HTTP Client (commons-httpclient:*) - http://commons.apache.org/httpclient/license.html + * Apache Commons IO (commons-io:*) - http://commons.apache.org/io/license.html + * Apache Commons JXPath (commons-jxpath:*) - http://commons.apache.org/jxpath/license.html + * Apache Commons Lang (commons-lang:*) - http://commons.apache.org/lang/license.html + * Apache Commons Logging (commons-logging:*) - http://commons.apache.org/logging/license.html + * Apache Commons Pool (commons-pool:*) - http://commons.apache.org/pool/license.html + * Apache Commons Validator (commons-validator:*) - http://commons.apache.org/validator/license.html + * Apache Geronimo (org.apache.geronimo.specs:*) - http://geronimo.apache.org/ + * Apache HTTPComponents (org.apache.httpcomponents:*) - http://hc.apache.org/ + * Apache Jakarta ORO (oro:*) - http://svn.apache.org/repos/asf/jakarta/oro/trunk/LICENSE + * Apache Jakarta Regexp (jakarta-regexp:*) - http://jakarta.apache.org/regexp/ + * Apache JaxMe (jaxme:jaxme-api) - http://ws.apache.org/old/jaxme-old/license.html + * Apache Jena (com.hp.hpl.jena:*) - http://jena.apache.org/ + * Apache log4j (log4j:*) : http://logging.apache.org/log4j/ + * Apache Lucene (org.apache.lucene:*) - http://lucene.apache.org/ + * Apache PDFBox (org.apache.pdfbox:*) - http://pdfbox.apache.org/ + * Apache POI (org.apache.poi:*) - http://poi.apache.org/ + * Apache Solr (org.apache.solr:*) - http://lucene.apache.org/solr/ + * Apache Xerces (xerces:*) - http://xerces.apache.org/ + * Apache XML Commons (xml-apis:*) - http://xerces.apache.org/xml-commons/licenses.html + * Apache XML Project (xalan:*) - http://xml.apache.org/xalan-j/#license + * Apache XMLBeans (org.apache.xmlbeans:*) - http://xmlbeans.apache.org/ + * Apache ZooKeeper (org.apache.zookeeper:*) - http://zookeeper.apache.org/ + * Databene ContiPerf (org.databene:contiperf) - http://databene.org/contiperf + * Ehcache (net.sf.ehcache:*) - http://ehcache.org/about/license + * ElasticSearch (org.elasticsearch:*) - http://www.elasticsearch.org/ + * Evo Inflector (org.atteo:*) - http://www.atteo.org/evo-framework/inflector/ + * flexjson (net.sf.flexjson:*) - http://sourceforge.net/projects/flexjson/ + * Google GSON (com.google.code.gson:*) - http://code.google.com/p/google-gson/ + * Google Guava (com.google.guava:*) - http://code.google.com/p/guava-libraries/ + * Jackson (org.codehaus.jackson:*) - http://jackson.codehaus.org/ + * Jettison (org.codejaus.jettison:*) - http://jettison.codehaus.org/ + * Jetty (org.mortbay.jetty:*) - http://jetty.codehaus.org/jetty/license.html + * Lyncode XOAI (com.lyncode:xoai) - http://www.lyncode.com/ + * noggit (org.noggit:noggit) - http://noggit.org/ + * oai4j (se.kb:oai4j) - http://oai4j-client.sourceforge.net/ + * OpenCSV (net.sf.opencsv:*) - http://opencsv.sourceforge.net/ + * Rome (net.java.dev.rome:*, org.rometools:*, rome:*) - http://rometools.org/ + * spatial4j (com.spatial4j:*) - http://spatial4j.com/ + * Spring Framework (org.springframework:*) - http://www.springsource.org/spring-framework + * SWORD Libraries (org.swordapp:*) - http://mvnrepository.com/artifact/org.swordapp/server/2.0 + * Woodstox (org.codehaus.woodstox:*) - http://woodstox.codehaus.org/Download + +BSD License (http://www.opensource.org/licenses/BSD-3-Clause) + * asm (asm:*) - http://asm.ow2.org/ + * Biblio Transformation Engine (gr.ekt:biblio-transformation-engine) - http://code.google.com/p/biblio-transformation-engine/ + * DNSJava (org.dspace.dnsjava:dnsjava)- http://www.xbill.org/dnsjava/dnsjava-current/README + * dom4j (dom4j:*, maven:dom4j) - http://dom4j.sourceforge.net/dom4j-1.6.1/license.html + * Foresite Toolkit (com.googlecode.foresite-toolkit:*) - http://code.google.com/p/foresite-toolkit/ + * jargon (org.dspace:jargon) - http://www.sdsc.edu/srb/index.php/Jargon + * Java BibTeX Parser (org.jbibtex:*) - https://code.google.com/p/java-bibtex/ + * Jaxen (jaxen:*) - http://jaxen.codehaus.org/license.html + * JLine (jline:*) - http://jline.sourceforge.net/ + * JUnitPerf (junitperf:*) - http://www.clarkware.com/software/JUnitPerf.html#license + * MSV (msv:*) - http://msv.java.net/ + * StAX (Streaming API for XML) (stax:*) - http://stax.codehaus.org/ + * XMLUnit (xmlunit:*) - http://xmlunit.sourceforge.net/ + * YUI (com.yahoo.platform.yui:*) - http://yuilibrary.com/license/ + +Common Development and Distribution License (CDDL) v1.0 (http://www.opensource.org/licenses/CDDL-1.0) + * JavaBeans Activation Framework (javax.activation:*) - http://www.opensource.org/licenses/CDDL-1.0 + * Java Mail (javax.mail:*) - http://www.opensource.org/licenses/CDDL-1.0 + * JAX-RPC (javax.xml:jaxrpc-api) - http://java.net/projects/jax-rpc/ + +Common Development and Distribution License (CDDL) v1.1 (http://glassfish.java.net/public/CDDL+GPL_1_1.html) + * JAXB (com.sun.xml.bind:*) - http://jaxb.java.net/ + * Jersey (com.sun.jersey.*) - https://jersey.java.net/ + +Common Public License v1.0 (http://www.opensource.org/licenses/cpl1.0) + * JUnit (junit:*) - http://junit.org/license + * WSDL4J (wsdl4j:*) - http://sourceforge.net/projects/wsdl4j/ + +Lesser GPL (http://www.opensource.org/licenses/LGPL-2.1) + * JExcelAPI (net.sourceforge.jexcelapi:*) - http://sourceforge.net/projects/jexcelapi/ + * MaxMind GeoIP (org.dspace.dependencies:dspace-geoip) - http://geoip.cvs.sourceforge.net/viewvc/geoip/java/LICENSE + * METS Java Toolkit (org.dspace.mets:*) - http://hul.harvard.edu/mets/ + * Text-mining (org.dspace.dependencies:dspace-tm-extractors) - http://code.google.com/p/text-mining/ + * XOM (xom:*) - http://www.xom.nu/ + +MIT / X11 License (or adaptations) (http://www.opensource.org/licenses/MIT) + * Bouncy Castle (org.bouncycastle:*) - http://www.bouncycastle.org/licence.html + * jmockit (org.dspace.dependencies.jmockit:dspace-jmockit) - http://code.google.com/p/jmockit/ + * SLF4J (org.slf4j:*) - http://www.slf4j.org/license.html + +Mozilla Public License (http://www.opensource.org/licenses/MPL-2.0) + * H2 database (com.h2database:*) - http://www.h2database.com/html/license.html + +New BSD License (http://opensource.org/licenses/bsd-license.php) + * Biblio-Transformation Engine (gr.ekt.bte:*) - http://github.com/EKT/Biblio-Transformation-Engine + +Other Open Source Licenses: + * AOP Alliance (aopalliance:*) - Public Domain: http://aopalliance.sourceforge.net/ + * backport-util-concurrent (backport-util-concurrent:*) - Public Domain: http://creativecommons.org/licenses/publicdomain + * coverity-escapers (com.coverity.security:*) - Modified BSD + * Handle API (org.dspace:handle) - Handle Public License Agreement: http://www.handle.net/HSj/hdlnet-2-LICENSE.pdf + * ICU4J (com.ibm.icu:icu4j) - ICU License : http://source.icu-project.org/repos/icu/icu/trunk/license.html + * JDOM (jdom:*) - JDOM License : https://github.com/hunterhacker/jdom/blob/master/LICENSE.txt + * OCLC Harvester2 (org.dspace:oclc-harvester2) - OCLC Research Public License: http://www.oclc.org/research/activities/software/license/v2final.html + * PostgreSQL (postgresql:*) - PostgreSQL License (BSD-based): http://www.postgresql.org/about/licence/ + * Pull-parser / XPP3 (pull-parser:*, xpp3:*) - Indiana University Extreme! Lab Software License (BSD-based): http://www.extreme.indiana.edu/xgws/xsoap/xpp/download/PullParser2/LICENSE.txt + +---- +NOTE #1: Some individual web application files in DSpace (e.g. Javascript +libraries, CSS Frameworks) may have their own open source license. In that +scenario, we place a copy of the full text of the license alongside the +licensed files. You can locate these additional licenses in our codebase +by searching for files with a ".LICENSE" file extension. + +For example, on Linux you can use the 'find' command from the source directory: + +find . -type f -name "*.LICENSE" +---- + +---- +NOTE #2: Although we try to keep this libraries list current, the latest +information about DSpace third party libraries can be found by running the +following Maven command(s): + +mvn project-info-reports:dependencies + +This generates a "[project]/target/site/dependencies.html" report under every +DSpace project directory. This report lists all dependencies and their license +(if it can be determined by Maven). + +Additionally, you may wish to run: + +mvn project-info-reports:dependency-convergence + +This generates a summary report at +"[dspace]/target/site/dependency-convergence.html" which lists all dependencies +of all DSpace projects (though it does not list license information) + +For more information see the maven-project-info-reports-plugin: +http://maven.apache.org/plugins/maven-project-info-reports-plugin/ +---- diff --git a/README b/README new file mode 100644 index 0000000000000000000000000000000000000000..0788ec5eb9ac3217fc60909f86e96af57cf7a2f4 --- /dev/null +++ b/README @@ -0,0 +1,57 @@ +Installation instructions may be found in DSpace-Manual.pdf, offered +with the source archives in the SourceForge project: + + http://sourceforge.net/projects/dspace/files/DSpace%20Stable/VERSION/ + +(Replace "VERSION" with the version you are installing, such as "4.0".) + +DSpace version information can be viewed online at + - https://wiki.duraspace.org/display/DSDOC/ + +Documentation for the most recent stable release(s) may be downloaded +or viewed online at + - http://www.dspace.org/latest-release/ + - https://wiki.duraspace.org/display/DSDOC/ + +In addition, a listing of all known contributors to DSpace software can be +found online at: +https://wiki.duraspace.org/display/DSPACE/DSpaceContributors + +Installation instructions for other versions may be different, so you +are encouraged to obtain the appropriate version of the Documentation +(from the links above or from the source repository). + +To obtain files from the repository and build, please see: + + - https://github.com/DSpace/DSpace/ + +or just: + + - git clone git://github.com/DSpace/DSpace.git + +Please refer any further problems to the dspace-tech@lists.sourceforge.net +mailing list. + + - http://sourceforge.net/mail/?group_id=19984 + + +Detailed Issue Tracking for DSpace is done on our JIRA Issue Tracker + + - https://jira.duraspace.org/browse/DS + + +To contribute to DSpace, please see: + + - https://wiki.duraspace.org/display/DSPACE/How+to+Contribute+to+DSpace + + +For more details about DSpace, including a list of service providers, +places to seek help, news articles and lists of other users, please see: + + - http://www.dspace.org/ + + +DSpace source code licensing information available online at: + - http://www.dspace.org/license/ + +Copyright (c) 2002-2013, DuraSpace. All rights reserved. diff --git a/build.properties b/build.properties new file mode 100644 index 0000000000000000000000000000000000000000..b054143a6db11e16755ba51aa5a6e42da948f25d --- /dev/null +++ b/build.properties @@ -0,0 +1,167 @@ +# DSpace build.properties +# This file should be customised to suit your build environment. +# Note that not all configuration is handled here, only the most common +# properties that tend to differ between build environments. +# For adjusting global settings or more complex settings, edit the relevant config file. +# +# IMPORTANT: Do not remove or comment out settings in build.properties +# When you edit the "build.properties" file (or a custom *.properties file), +# take care not to remove or comment out any settings. Doing so, may cause +# your final "dspace.cfg" file to be misconfigured with regards to that +# particular setting. Instead, if you wish to remove/disable a particular +# setting, just clear out its value. For example, if you don't want to be +# notified of new user registrations, ensure the "mail.registration.notify" +# setting has no value, e.g. "mail.registration.notify=" +# + +########################## +# SERVER CONFIGURATION # +########################## + +# DSpace installation directory. This is the location where you want +# to install DSpace. NOTE: this value will be copied over to the +# "dspace.dir" setting in the final "dspace.cfg" file. It can be +# modified later on in your "dspace.cfg", if needed. +dspace.install.dir=/home/dspace/webapp/ + +# DSpace host name - should match base URL. Do not include port number +dspace.hostname = dspacesnj.c3sl.ufpr.br + +# DSpace base host URL. Include port number etc. +dspace.baseUrl = http://dspacesnj.c3sl.ufpr.br:8080 + +# DSpace base host URL for mobile access. Include port number etc. +dspace.baseMobileUrl = http://m.dspacesnj.c3sl.ufpr.br:8080 + +# Base URL of the server hosting the iframe +dspace.iframeBaseURL = http://participatorio.juventude.gov.br/biblioteca + +# Name of the site +dspace.name = Biblioteca Digital do Participatório - Observatório Participativo da Juventude + +# Solr server +solr.server=http://localhost:8080/solr + +# Default language for metadata values +default.language = pt_BR + +########################## +# DATABASE CONFIGURATION # +########################## + +# Database name ("oracle", or "postgres") +db.name=postgres + +# Uncomment the appropriate block below for your database. +# postgres +db.driver=org.postgresql.Driver +db.url=jdbc:postgresql://localhost:5432/dspace +db.username=dspace +db.password=dspace + +# oracle +#db.driver= oracle.jdbc.OracleDriver +#db.url=jdbc:oracle:thin:@//localhost:1521/xe +#db.username=dspace +#db.password=dspace + +# Schema name - if your database contains multiple schemas, you can avoid problems with +# retrieving the definitions of duplicate object names by specifying +# the schema name here that is used for DSpace by uncommenting the following entry +db.schema = + +# Maximum number of DB connections in pool +db.maxconnections = 30 + +# Maximum time to wait before giving up if all connections in pool are busy (milliseconds) +db.maxwait = 5000 + +# Maximum number of idle connections in pool (-1 = unlimited) +db.maxidle = -1 + +# Determine if prepared statement should be cached. (default is true) +db.statementpool = true + +# Specify a name for the connection pool (useful if you have multiple applications sharing Tomcat's dbcp) +# If not specified, defaults to 'dspacepool' +db.poolname = dspacepool + +####################### +# EMAIL CONFIGURATION # +####################### + +# SMTP mail server +mail.server = smtp.c3sl.ufpr.br + +# SMTP mail server authentication username and password (if required) +# mail.server.username = myusername +# mail.server.password = mypassword +mail.server.username= +mail.server.password= + +# SMTP mail server alternate port (defaults to 25) +mail.server.port = 25 + +# From address for mail +mail.from.address = dsparticipatorio@c3sl.ufpr.br + +# Currently limited to one recipient! +mail.feedback.recipient = dsparticipatorio@c3sl.ufpr.br + +# General site administration (Webmaster) e-mail +mail.admin = dsparticipatorio@c3sl.ufpr.br + +# Recipient for server errors and alerts +#mail.alert.recipient = email-address-here +mail.alert.recipient=dsparticipatorio@c3sl.ufpr.br + +# Recipient for new user registration emails +#mail.registration.notify = email-address-here +mail.registration.notify=dsparticipatorio@c3sl.ufpr.br + + +######################## +# HANDLE CONFIGURATION # +######################## + +# Canonical Handle URL prefix +# +# By default, DSpace is configured to use http://hdl.handle.net/ +# as the canonical URL prefix when generating dc.identifier.uri +# during submission, and in the 'identifier' displayed in JSPUI +# item record pages. +# +# If you do not subscribe to CNRI's handle service, you can change this +# to match the persistent URL service you use, or you can force DSpace +# to use your site's URL, eg. +#handle.canonical.prefix = ${dspace.url}/handle/ +# +# Note that this will not alter dc.identifer.uri metadata for existing +# items (only for subsequent submissions), but it will alter the URL +# in JSPUI's 'identifier' message on item record pages for existing items. +# +# If omitted, the canonical URL prefix will be http://hdl.handle.net/ +handle.canonical.prefix = http://hdl.handle.net/ + +# CNRI Handle prefix +handle.prefix = 11322 + +####################### +# PROXY CONFIGURATION # +####################### +# uncomment and specify both properties if proxy server required +# proxy server for external http requests - use regular hostname without port number +http.proxy.host = + +# port number of proxy server +http.proxy.port = + +##################### +# LOGLEVEL SETTINGS # +##################### +loglevel.other = INFO +# loglevel.other: Log level for other third-party tools/APIs used by DSpace +# Possible values (from most to least info): DEBUG, INFO, WARN, ERROR, FATAL +loglevel.dspace = INFO +# loglevel.dspace: Log level for all DSpace-specific code (org.dspace.*) +# Possible values (from most to least info): DEBUG, INFO, WARN, ERROR, FATAL diff --git a/dspace-rest/README.md b/dspace-rest/README.md new file mode 100644 index 0000000000000000000000000000000000000000..404a986878f2fb71be96a4d739725682f8339e1f --- /dev/null +++ b/dspace-rest/README.md @@ -0,0 +1,75 @@ +#DSpace REST API (Jersey) + +A RESTful web services API for DSpace, built using JAX-RS1 JERSEY. + +##Getting Started +This REST API is integrated directly into the DSpace code-base. + + * Rebuild as normal: mvn + ant + * Deploy the webapp (i.e to tomcat) + * ```<Context path="/rest" docBase="/dspace/webapps/rest" allowLinking="true"/>``` + + +At this point, this is a READ ONLY API for DSpace, for the anonymous user. Only Anonymous READ Communities, Collections, Items, and Bitstreams are available. + +##Endpoints + +| Resource |CREATE|READ list|READ single|Edit|Delete|Search| +| ------------- |------|:-------:|-----------|----|------|------| +| /communities | | Y | Y | | | | +| /collections | | Y | Y | | | | +| /items | | | Y | | | | +| /bitstreams | | | Y | | | || + + +###Communities +View the list of top-level communities +- http://localhost:8080/rest/communities + +View a specific community +- http://localhost:8080/rest/communities/:ID + +View a specific community, list its subcommunities, and subcollections +- http://localhost:8080/rest/communities/:ID?expand=all + +###Collections +View the list of collections +- http://localhost:8080/rest/collections + +View a specific collection +- http://localhost:8080/rest/collections/:ID + +View a specific collection, and its items +- http://localhost:8080/rest/collections/:ID?expand=all + +###Items +View an Item, and see its bitstreams +- http://localhost:8080/rest/items/:ID + +###Bitstreams +View information about a bitstream +- http://localhost:8080/rest/bitstreams/:ID + +View/Download a specific Bitstream +- http://localhost:8080/rest/bitstreams/:ID/retrieve + +####Statistics +Recording of statistics for view of items or download of bitstreams (set stats = true in rest.cfg to enable stats recording) +http://localhost:8080/rest/items/:ID?userIP=ip&userAgent=userAgent&xforwarderfor=xforwarderfor +If no parameters are given the details of httprequest sender are used in statistics. +This enables tools to record the details of their user rather then themselves. + + +###Handles +Lookup a DSpaceObject by its Handle, this produces the name/ID, that you lookup in /bitstreams, /items, /collections, /communities +- http://localhost:8080/rest/handle/{prefix}/{suffix} + +##Expand +There is an ?expand= query parameter for more expensive operations. You can tack it on the end of endpoints. +It is optional, all, some or none. The response will usually indicate what the available "expand" options are. + +##HTTP Responses +* 200 OK - We have the requested object/objects +* 401 Unauthorized - The anonymous user does not have READ access to that object +* 404 Not Found - That object doesn't exist +* 500 Server Error - Likely a SQLException, IOException, more details in the logs. \ No newline at end of file diff --git a/dspace-rest/pom.xml b/dspace-rest/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..b08f62cfc245ebdaee6f0bfbe459d19422c70d6a --- /dev/null +++ b/dspace-rest/pom.xml @@ -0,0 +1,129 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.dspace</groupId> + <artifactId>dspace-rest</artifactId> + <packaging>war</packaging> + <version>4.1</version> + <name>DSpace RESTful web services API</name> + <url>http://demo.dspace.org</url> + + <parent> + <groupId>org.dspace</groupId> + <artifactId>dspace-parent</artifactId> + <version>4.1</version> + <relativePath>..</relativePath> + </parent> + + <properties> + <!-- This is the path to the root [dspace-src] directory. --> + <root.basedir>${basedir}/..</root.basedir> + </properties> + + <dependencies> + <!-- Jersey, for RESTful web services --> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-server</artifactId> + <version>1.17.1</version> + </dependency> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-servlet</artifactId> + <version>1.17.1</version> + </dependency> + <!-- JSON serialization, should I use jackson?--> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-json</artifactId> + <version>1.17.1</version> + </dependency> + + + + <!-- Spring 3 dependencies --> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-core</artifactId> + </dependency> + + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-context</artifactId> + </dependency> + + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-web</artifactId> + </dependency> + + + <!-- Jersey + Spring --> + <dependency> + <groupId>com.sun.jersey.contribs</groupId> + <artifactId>jersey-spring</artifactId> + <version>1.8</version> + <exclusions> + <exclusion> + <groupId>org.springframework</groupId> + <artifactId>spring</artifactId> + </exclusion> + <exclusion> + <groupId>org.springframework</groupId> + <artifactId>spring-core</artifactId> + </exclusion> + <exclusion> + <groupId>org.springframework</groupId> + <artifactId>spring-web</artifactId> + </exclusion> + <exclusion> + <groupId>org.springframework</groupId> + <artifactId>spring-beans</artifactId> + </exclusion> + <exclusion> + <groupId>org.springframework</groupId> + <artifactId>spring-context</artifactId> + </exclusion> + <exclusion> + <groupId>org.springframework</groupId> + <artifactId>spring-aop</artifactId> + </exclusion> + </exclusions> + </dependency> + + + <!-- Use DSpace, for now, an older version to minimize spring generated dependency on Discovery --> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>dspace-api</artifactId> + </dependency> + + <!-- Connecting to DSpace datasource sets a dependency on Postgres DB--> + <dependency> + <groupId>commons-dbcp</groupId> + <artifactId>commons-dbcp</artifactId> + </dependency> + <dependency> + <groupId>postgresql</groupId> + <artifactId>postgresql</artifactId> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> + <version>3.1.0</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.atteo</groupId> + <artifactId>evo-inflector</artifactId> + <version>1.0.1</version> + </dependency> + <dependency> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + </dependency> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>dspace-services</artifactId> + </dependency> + </dependencies> +</project> diff --git a/dspace-rest/src/main/java/org/dspace/rest/BitstreamResource.java b/dspace-rest/src/main/java/org/dspace/rest/BitstreamResource.java new file mode 100644 index 0000000000000000000000000000000000000000..34e2c413353ebad57bd59ab7653899c7d1f82fec --- /dev/null +++ b/dspace-rest/src/main/java/org/dspace/rest/BitstreamResource.java @@ -0,0 +1,140 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.rest; + +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeException; +import org.dspace.authorize.AuthorizeManager; +import org.dspace.content.DSpaceObject; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Constants; +import org.dspace.rest.common.Bitstream; +import org.dspace.usage.UsageEvent; +import org.dspace.utils.DSpace; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.*; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.sql.SQLException; + +/** + * Created with IntelliJ IDEA. + * User: peterdietz + * Date: 10/2/13 + * Time: 5:56 PM + * To change this template use File | Settings | File Templates. + */ +@Path("/bitstreams") +public class BitstreamResource { + Logger log = Logger.getLogger(BitstreamResource.class); + private static org.dspace.core.Context context; + + private static final boolean writeStatistics; + + static{ + writeStatistics=ConfigurationManager.getBooleanProperty("rest","stats",false); + } + + //BitstreamList - Not Implemented + + @GET + @Path("/{bitstream_id}") + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public Bitstream getBitstream(@PathParam("bitstream_id") Integer bitstream_id, @QueryParam("expand") String expand) { + try { + if(context == null || !context.isValid()) { + context = new org.dspace.core.Context(); + //Failed SQL is ignored as a failed SQL statement, prevent: current transaction is aborted, commands ignored until end of transaction block + context.getDBConnection().setAutoCommit(true); + } + + org.dspace.content.Bitstream bitstream = org.dspace.content.Bitstream.find(context, bitstream_id); + + if(AuthorizeManager.authorizeActionBoolean(context, bitstream, org.dspace.core.Constants.READ)) { + return new org.dspace.rest.common.Bitstream(bitstream, expand); + } else { + throw new WebApplicationException(Response.Status.UNAUTHORIZED); + } + } catch(SQLException e) { + log.error(e.getMessage()); + throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); + } + } + + @GET + @Path("/{bitstream_id}/retrieve") + public javax.ws.rs.core.Response getFile(@PathParam("bitstream_id") final Integer bitstream_id, + @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, @QueryParam("xforwarderfor") String xforwarderfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) { + try { + if(context == null || !context.isValid() ) { + context = new org.dspace.core.Context(); + //Failed SQL is ignored as a failed SQL statement, prevent: current transaction is aborted, commands ignored until end of transaction block + context.getDBConnection().setAutoCommit(true); + } + + org.dspace.content.Bitstream bitstream = org.dspace.content.Bitstream.find(context, bitstream_id); + if(AuthorizeManager.authorizeActionBoolean(context, bitstream, org.dspace.core.Constants.READ)) { + if(writeStatistics){ + writeStats(bitstream_id, user_ip, user_agent, xforwarderfor, headers, request); + } + + return Response.ok(bitstream.retrieve()).type(bitstream.getFormat().getMIMEType()).build(); + } else { + throw new WebApplicationException(Response.Status.UNAUTHORIZED); + } + + } catch (IOException e) { + log.error(e.getMessage()); + throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); + } catch (SQLException e) { + log.error(e.getMessage()); + throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); + } catch (AuthorizeException e) { + log.error(e.getMessage()); + throw new WebApplicationException(Response.Status.UNAUTHORIZED); + } + } + + private void writeStats(Integer bitstream_id, String user_ip, String user_agent, + String xforwarderfor, HttpHeaders headers, + HttpServletRequest request) { + + try{ + DSpaceObject bitstream = DSpaceObject.find(context, Constants.BITSTREAM, bitstream_id); + + if(user_ip==null || user_ip.length()==0){ + new DSpace().getEventService().fireEvent( + new UsageEvent( + UsageEvent.Action.VIEW, + request, + context, + bitstream)); + } else{ + new DSpace().getEventService().fireEvent( + new UsageEvent( + UsageEvent.Action.VIEW, + user_ip, + user_agent, + xforwarderfor, + context, + bitstream)); + } + log.debug("fired event"); + + } catch(SQLException ex){ + log.error("SQL exception can't write usageEvent \n" + ex); + } + + } + +} diff --git a/dspace-rest/src/main/java/org/dspace/rest/CollectionsResource.java b/dspace-rest/src/main/java/org/dspace/rest/CollectionsResource.java new file mode 100644 index 0000000000000000000000000000000000000000..476f505d96ae3eee9f4de9aa37d57a811afa9812 --- /dev/null +++ b/dspace-rest/src/main/java/org/dspace/rest/CollectionsResource.java @@ -0,0 +1,178 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.rest; + + +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeManager; +import org.dspace.content.DSpaceObject; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Constants; +import org.dspace.rest.common.Collection; +import org.dspace.usage.UsageEvent; +import org.dspace.utils.DSpace; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.ServletContext; +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import java.sql.SQLException; +import java.util.ArrayList; + +/* +The "Path" annotation indicates the URI this class will be available at relative to your base URL. For +example, if this web-app is launched at localhost using a context of "hello" and no URL pattern is defined +in the web.xml servlet mapping section, then the web service will be available at: + +http://localhost:8080/<webapp>/collections + */ +@Path("/collections") +public class CollectionsResource { + private static Logger log = Logger.getLogger(CollectionsResource.class); + + + @javax.ws.rs.core.Context ServletContext servletContext; + + private static org.dspace.core.Context context; + + private static final boolean writeStatistics; + + static{ + writeStatistics=ConfigurationManager.getBooleanProperty("rest","stats",false); + } + + /* + The "GET" annotation indicates this method will respond to HTTP Get requests. + The "Produces" annotation indicates the MIME response the method will return. + */ + @GET + @Path("/") + @Produces(MediaType.TEXT_HTML) + public String listHTML() { + StringBuilder everything = new StringBuilder(); + try { + if(context == null || !context.isValid() ) { + context = new org.dspace.core.Context(); + //Failed SQL is ignored as a failed SQL statement, prevent: current transaction is aborted, commands ignored until end of transaction block + context.getDBConnection().setAutoCommit(true); + } + + org.dspace.content.Collection[] collections = org.dspace.content.Collection.findAll(context); + for(org.dspace.content.Collection collection : collections) { + //TODO check auth... + everything.append("<li><a href='" + servletContext.getContextPath() + "/collections/" + collection.getID() + "'>" + collection.getID() + " - " + collection.getName() + "</a></li>\n"); + } + + return "<html><title>Hello!</title><body>Collections<br/><ul>" + everything.toString() + "</ul>.</body></html> "; + + } catch (SQLException e) { + log.error(e.getMessage()); + throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); + } + } + + @GET + @Path("/") + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public org.dspace.rest.common.Collection[] list(@QueryParam("expand") String expand, @QueryParam("limit") @DefaultValue("100") Integer limit, @QueryParam("offset") @DefaultValue("0") Integer offset) { + try { + if(context == null || !context.isValid() ) { + context = new org.dspace.core.Context(); + //Failed SQL is ignored as a failed SQL statement, prevent: current transaction is aborted, commands ignored until end of transaction block + context.getDBConnection().setAutoCommit(true); + } + + org.dspace.content.Collection[] collections; + + //Only support paging if limit/offset are 0 or positive values. + if(limit != null && limit >= 0 && offset != null && offset >= 0) { + collections = org.dspace.content.Collection.findAll(context, limit, offset); + } else { + collections = org.dspace.content.Collection.findAll(context); + } + + ArrayList<org.dspace.rest.common.Collection> collectionArrayList = new ArrayList<org.dspace.rest.common.Collection>(); + for(org.dspace.content.Collection collection : collections) { + if(AuthorizeManager.authorizeActionBoolean(context, collection, org.dspace.core.Constants.READ)) { + org.dspace.rest.common.Collection restCollection = new org.dspace.rest.common.Collection(collection, null, context, limit, offset); + collectionArrayList.add(restCollection); + } // Not showing restricted-access collections + } + + return collectionArrayList.toArray(new org.dspace.rest.common.Collection[0]); + + } catch (SQLException e) { + log.error(e.getMessage()); + throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); + } + } + + @GET + @Path("/{collection_id}") + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public org.dspace.rest.common.Collection getCollection(@PathParam("collection_id") Integer collection_id, @QueryParam("expand") String expand, + @QueryParam("limit") @DefaultValue("100") Integer limit, @QueryParam("offset") @DefaultValue("0") Integer offset, + @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, @QueryParam("xforwarderfor") String xforwarderfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) { + try { + if(context == null || !context.isValid() ) { + context = new org.dspace.core.Context(); + //Failed SQL is ignored as a failed SQL statement, prevent: current transaction is aborted, commands ignored until end of transaction block + context.getDBConnection().setAutoCommit(true); + } + + org.dspace.content.Collection collection = org.dspace.content.Collection.find(context, collection_id); + if(AuthorizeManager.authorizeActionBoolean(context, collection, org.dspace.core.Constants.READ)) { + if(writeStatistics){ + writeStats(collection_id, user_ip, user_agent, xforwarderfor, headers, request); + } + return new org.dspace.rest.common.Collection(collection, expand, context, limit, offset); + } else { + throw new WebApplicationException(Response.Status.UNAUTHORIZED); + } + } catch (SQLException e) { + log.error(e.getMessage()); + throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); + } + } + + private void writeStats(Integer collection_id, String user_ip, String user_agent, + String xforwarderfor, HttpHeaders headers, + HttpServletRequest request) { + + try{ + DSpaceObject collection = DSpaceObject.find(context, Constants.COLLECTION, collection_id); + + if(user_ip==null || user_ip.length()==0){ + new DSpace().getEventService().fireEvent( + new UsageEvent( + UsageEvent.Action.VIEW, + request, + context, + collection)); + } else{ + new DSpace().getEventService().fireEvent( + new UsageEvent( + UsageEvent.Action.VIEW, + user_ip, + user_agent, + xforwarderfor, + context, + collection)); + } + log.debug("fired event"); + + } catch(SQLException ex){ + log.error("SQL exception can't write usageEvent \n" + ex); + } + + } +} diff --git a/dspace-rest/src/main/java/org/dspace/rest/CommunitiesResource.java b/dspace-rest/src/main/java/org/dspace/rest/CommunitiesResource.java new file mode 100644 index 0000000000000000000000000000000000000000..3be038972de9950ad5d3e2dfec1a5cf8b6e4f802 --- /dev/null +++ b/dspace-rest/src/main/java/org/dspace/rest/CommunitiesResource.java @@ -0,0 +1,163 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.rest; + +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeManager; +import org.dspace.content.DSpaceObject; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Constants; +import org.dspace.usage.UsageEvent; +import org.dspace.utils.DSpace; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.ServletContext; +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import java.sql.SQLException; +import java.util.ArrayList; + +/* +The "Path" annotation indicates the URI this class will be available at relative to your base URL. For +example, if this web-app is launched at localhost using a context of "hello" and no URL pattern is defined +in the web.xml servlet mapping section, then the web service will be available at: + +http://localhost:8080/<webapp>/communities + */ +@Path("/communities") +public class CommunitiesResource { + private static Logger log = Logger.getLogger(CommunitiesResource.class); + + private static org.dspace.core.Context context; + + private static final boolean writeStatistics; + + static{ + writeStatistics=ConfigurationManager.getBooleanProperty("rest","stats",false); + } + + /* + The "GET" annotation indicates this method will respond to HTTP Get requests. + The "Produces" annotation indicates the MIME response the method will return. + */ + @GET + @Produces(MediaType.TEXT_HTML) + public String list() { + StringBuilder everything = new StringBuilder(); + try { + if(context == null || !context.isValid() ) { + context = new org.dspace.core.Context(); + //Failed SQL is ignored as a failed SQL statement, prevent: current transaction is aborted, commands ignored until end of transaction block + context.getDBConnection().setAutoCommit(true); + } + org.dspace.content.Community[] communities = org.dspace.content.Community.findAllTop(context); + for(org.dspace.content.Community community : communities) { + everything.append(community.getName() + "<br/>\n"); + } + return "<html><title>Hello!</title><body>Communities:<br/>" + everything.toString() + ".</body></html> "; + + } catch (SQLException e) { + log.error(e.getMessage()); + throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); + } + } + + //TODO Respond to html for communities/:id + + @GET + @Path("/") + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public org.dspace.rest.common.Community[] list(@QueryParam("expand") String expand) { + try { + if(context == null || !context.isValid() ) { + context = new org.dspace.core.Context(); + //Failed SQL is ignored as a failed SQL statement, prevent: current transaction is aborted, commands ignored until end of transaction block + context.getDBConnection().setAutoCommit(true); + } + + org.dspace.content.Community[] topCommunities = org.dspace.content.Community.findAllTop(context); + ArrayList<org.dspace.rest.common.Community> communityArrayList = new ArrayList<org.dspace.rest.common.Community>(); + for(org.dspace.content.Community community : topCommunities) { + if(AuthorizeManager.authorizeActionBoolean(context, community, org.dspace.core.Constants.READ)) { + //Only list communities that this user has access to. + org.dspace.rest.common.Community restCommunity = new org.dspace.rest.common.Community(community, expand, context); + communityArrayList.add(restCommunity); + } + } + + return communityArrayList.toArray(new org.dspace.rest.common.Community[0]); + + } catch (SQLException e) { + log.error(e.getMessage()); + throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); + } //finally? + } + + @GET + @Path("/{community_id}") + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public org.dspace.rest.common.Community getCommunity(@PathParam("community_id") Integer community_id, @QueryParam("expand") String expand, + @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, @QueryParam("xforwarderfor") String xforwarderfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) { + try { + if(context == null || !context.isValid() ) { + context = new org.dspace.core.Context(); + //Failed SQL is ignored as a failed SQL statement, prevent: current transaction is aborted, commands ignored until end of transaction block + context.getDBConnection().setAutoCommit(true); + } + + org.dspace.content.Community community = org.dspace.content.Community.find(context, community_id); + if(AuthorizeManager.authorizeActionBoolean(context, community, org.dspace.core.Constants.READ)) { + if(writeStatistics){ + writeStats(community_id, user_ip, user_agent, xforwarderfor, headers, request); + } + return new org.dspace.rest.common.Community(community, expand, context); + } else { + throw new WebApplicationException(Response.Status.UNAUTHORIZED); + } + } catch (SQLException e) { + log.error(e.getMessage()); + throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); + } //finally? + } + + private void writeStats(Integer community_id, String user_ip, String user_agent, + String xforwarderfor, HttpHeaders headers, + HttpServletRequest request) { + + try{ + DSpaceObject community = DSpaceObject.find(context, Constants.COMMUNITY, community_id); + + if(user_ip==null || user_ip.length()==0){ + new DSpace().getEventService().fireEvent( + new UsageEvent( + UsageEvent.Action.VIEW, + request, + context, + community)); + } else{ + new DSpace().getEventService().fireEvent( + new UsageEvent( + UsageEvent.Action.VIEW, + user_ip, + user_agent, + xforwarderfor, + context, + community)); + } + log.debug("fired event"); + + } catch(SQLException ex){ + log.error("SQL exception can't write usageEvent \n" + ex); + } + + } +} diff --git a/dspace-rest/src/main/java/org/dspace/rest/HandleResource.java b/dspace-rest/src/main/java/org/dspace/rest/HandleResource.java new file mode 100644 index 0000000000000000000000000000000000000000..25270f301fafa4569d23c1dcc05bd54292d97e44 --- /dev/null +++ b/dspace-rest/src/main/java/org/dspace/rest/HandleResource.java @@ -0,0 +1,73 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.rest; + +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeManager; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.handle.HandleManager; +import org.dspace.rest.common.Collection; +import org.dspace.rest.common.Community; +import org.dspace.rest.common.DSpaceObject; +import org.dspace.rest.common.Item; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.sql.SQLException; + +/** + * Created with IntelliJ IDEA. + * User: peterdietz + * Date: 10/7/13 + * Time: 1:54 PM + * To change this template use File | Settings | File Templates. + */ +@Path("/handle") +public class HandleResource { + private static Logger log = Logger.getLogger(HandleResource.class); + private static org.dspace.core.Context context; + + @GET + @Path("/{prefix}/{suffix}") + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public org.dspace.rest.common.DSpaceObject getObject(@PathParam("prefix") String prefix, @PathParam("suffix") String suffix, @QueryParam("expand") String expand) { + try { + if(context == null || !context.isValid() ) { + context = new Context(); + //Failed SQL is ignored as a failed SQL statement, prevent: current transaction is aborted, commands ignored until end of transaction block + context.getDBConnection().setAutoCommit(true); + } + + org.dspace.content.DSpaceObject dso = HandleManager.resolveToObject(context, prefix + "/" + suffix); + if(dso == null) { + throw new WebApplicationException(Response.Status.NOT_FOUND); + } + log.info("DSO Lookup by handle: [" + prefix + "] / [" + suffix + "] got result of: " + dso.getTypeText() + "_" + dso.getID()); + + if(AuthorizeManager.authorizeActionBoolean(context, dso, org.dspace.core.Constants.READ)) { + switch(dso.getType()) { + case Constants.COMMUNITY: + return new Community((org.dspace.content.Community) dso, expand, context); + case Constants.COLLECTION: + return new Collection((org.dspace.content.Collection) dso, expand, context, null, null); + case Constants.ITEM: + return new Item((org.dspace.content.Item) dso, expand, context); + default: + return new DSpaceObject(dso); + } + } else { + throw new WebApplicationException(Response.Status.UNAUTHORIZED); + } + } catch (SQLException e) { + log.error(e.getMessage()); + throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); + } + } +} diff --git a/dspace-rest/src/main/java/org/dspace/rest/ItemsResource.java b/dspace-rest/src/main/java/org/dspace/rest/ItemsResource.java new file mode 100644 index 0000000000000000000000000000000000000000..cffd04dbd6ae1b3867dcb7a7b04748e4990da151 --- /dev/null +++ b/dspace-rest/src/main/java/org/dspace/rest/ItemsResource.java @@ -0,0 +1,114 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.rest; + +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeManager; +import javax.servlet.http.HttpServletRequest; + +import javax.ws.rs.*; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.sql.SQLException; + +import org.dspace.content.DSpaceObject; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Constants; +import org.dspace.usage.UsageEvent; +import org.dspace.utils.DSpace; + +/** + * Created with IntelliJ IDEA. + * User: peterdietz + * Date: 9/19/13 + * Time: 4:54 PM + * To change this template use File | Settings | File Templates. + */ +@Path("/items") +public class ItemsResource { + + private static final boolean writeStatistics; + + static{ + writeStatistics=ConfigurationManager.getBooleanProperty("rest","stats",false); + } + + /** log4j category */ + private static final Logger log = Logger.getLogger(ItemsResource.class); + //ItemList - Not Implemented + + private static org.dspace.core.Context context; + + @GET + @Path("/{item_id}") + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public org.dspace.rest.common.Item getItem(@PathParam("item_id") Integer item_id, @QueryParam("expand") String expand, + @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, @QueryParam("xforwarderfor") String xforwarderfor, + @Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException { + + + try { + if(context == null || !context.isValid()) { + context = new org.dspace.core.Context(); + //Failed SQL is ignored as a failed SQL statement, prevent: current transaction is aborted, commands ignored until end of transaction block + context.getDBConnection().setAutoCommit(true); + } + + org.dspace.content.Item item = org.dspace.content.Item.find(context, item_id); + + if(AuthorizeManager.authorizeActionBoolean(context, item, org.dspace.core.Constants.READ)) { + if(writeStatistics){ + writeStats(item_id, user_ip, user_agent, xforwarderfor, headers, request); + } + return new org.dspace.rest.common.Item(item, expand, context); + } else { + throw new WebApplicationException(Response.Status.UNAUTHORIZED); + } + + } catch (SQLException e) { + log.error(e.getMessage()); + throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); + } + } + + + private void writeStats(Integer item_id, String user_ip, String user_agent, + String xforwarderfor, HttpHeaders headers, + HttpServletRequest request) { + + try{ + DSpaceObject item = DSpaceObject.find(context, Constants.ITEM, item_id); + + if(user_ip==null || user_ip.length()==0){ + new DSpace().getEventService().fireEvent( + new UsageEvent( + UsageEvent.Action.VIEW, + request, + context, + item)); + } else{ + new DSpace().getEventService().fireEvent( + new UsageEvent( + UsageEvent.Action.VIEW, + user_ip, + user_agent, + xforwarderfor, + context, + item)); + } + log.debug("fired event"); + + } catch(SQLException ex){ + log.error("SQL exception can't write usageEvent \n" + ex); + } + + } + +} diff --git a/dspace-rest/src/main/java/org/dspace/rest/RestIndex.java b/dspace-rest/src/main/java/org/dspace/rest/RestIndex.java new file mode 100644 index 0000000000000000000000000000000000000000..3c0188f6767d05921d1c24d88724b2504c235851 --- /dev/null +++ b/dspace-rest/src/main/java/org/dspace/rest/RestIndex.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.rest; + +import javax.servlet.ServletContext; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +/* +Root of API, should have documentation on where to find the other resources. + */ +@Path("/") +public class RestIndex { + @javax.ws.rs.core.Context public static ServletContext servletContext; + + /* + The "GET" annotation indicates this method will respond to HTTP Get requests. + The "Produces" annotation indicates the MIME response the method will return. + */ + @GET + @Produces(MediaType.TEXT_HTML) + public String sayHtmlHello() { + return "<html><title>DSpace REST</title>" + + "<body><h1>DSpace REST API</h1>" + + "<ul>" + + "<li><a href='" + servletContext.getContextPath() + "/communities'>/communities</a></li>" + + "<li><a href='" + servletContext.getContextPath() + "/communities/1'>/communities/1</a></li>" + + "<li><a href='" + servletContext.getContextPath() + "/collections'>/collections</a></li>" + + "<li><a href='" + servletContext.getContextPath() + "/collections/1'>/collections/1</a></li>" + + "<li><a href='" + servletContext.getContextPath() + "/items'>/items</a></li>" + + "<li><a href='" + servletContext.getContextPath() + "/items/1'>/items/1</a></li>" + + "<li><a href='" + servletContext.getContextPath() + "/bitstreams'>/bitstreams</a></li>" + + "<li><a href='" + servletContext.getContextPath() + "/bitstreams/1'>/bitstreams/1</a></li>" + + "<li><a href='" + servletContext.getContextPath() + "/bitstreams/1/retrieve'>/bitstreams/1/retrieve</a></li>" + + "</ul>" + + "</body></html> "; + } +} diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/Bitstream.java b/dspace-rest/src/main/java/org/dspace/rest/common/Bitstream.java new file mode 100644 index 0000000000000000000000000000000000000000..ffe28af1c02998fd9987fb9edef6c8802588f51b --- /dev/null +++ b/dspace-rest/src/main/java/org/dspace/rest/common/Bitstream.java @@ -0,0 +1,156 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.rest.common; + +import org.apache.log4j.Logger; +import org.dspace.core.Constants; + +import javax.xml.bind.annotation.XmlRootElement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created with IntelliJ IDEA. + * User: peterdietz + * Date: 9/21/13 + * Time: 12:54 AM + * To change this template use File | Settings | File Templates. + */ +@XmlRootElement(name = "bitstream") +public class Bitstream extends DSpaceObject { + Logger log = Logger.getLogger(Bitstream.class); + + private String bundleName; + private String description; + private String format; + private String mimeType; + private Long sizeBytes; + private DSpaceObject parentObject; + private String retrieveLink; + private CheckSum checkSum; + private Integer sequenceId; + + public Bitstream() { + + } + + public Bitstream(org.dspace.content.Bitstream bitstream, String expand) throws SQLException{ + super(bitstream); + setup(bitstream, expand); + } + + public void setup(org.dspace.content.Bitstream bitstream, String expand) throws SQLException{ + List<String> expandFields = new ArrayList<String>(); + if(expand != null) { + expandFields = Arrays.asList(expand.split(",")); + } + + //A logo bitstream might not have a bundle... + if(bitstream.getBundles() != null & bitstream.getBundles().length >= 0) { + if(bitstream.getParentObject().getType() == Constants.ITEM) { + bundleName = bitstream.getBundles()[0].getName(); + } + } + + description = bitstream.getDescription(); + format = bitstream.getFormatDescription(); + sizeBytes = bitstream.getSize(); + retrieveLink = "/bitstreams/" + bitstream.getID() + "/retrieve"; + mimeType = bitstream.getFormat().getMIMEType(); + sequenceId = bitstream.getSequenceID(); + CheckSum checkSum = new CheckSum(); + checkSum.setCheckSumAlgorith(bitstream.getChecksumAlgorithm()); + checkSum.setValue(bitstream.getChecksum()); + this.setCheckSum(checkSum); + + if(expandFields.contains("parent") || expandFields.contains("all")) { + parentObject = new DSpaceObject(bitstream.getParentObject()); + } else { + this.addExpand("parent"); + } + + if(!expandFields.contains("all")) { + this.addExpand("all"); + } + } + + public Integer getSequenceId() { + return sequenceId; + } + + public void setSequenceId(Integer sequenceId) { + this.sequenceId = sequenceId; + } + + public String getBundleName() { + return bundleName; + } + + public void setBundleName(String bundleName) { + this.bundleName = bundleName; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setFormat(String format) { + this.format = format; + } + + public void setMimeType(String mimeType) { + this.mimeType = mimeType; + } + + public void setSizeBytes(Long sizeBytes) { + this.sizeBytes = sizeBytes; + } + + public void setParentObject(DSpaceObject parentObject) { + this.parentObject = parentObject; + } + + public void setRetrieveLink(String retrieveLink) { + this.retrieveLink = retrieveLink; + } + + public String getDescription() { + return description; + } + + public String getFormat() { + return format; + } + + public String getMimeType() { + return mimeType; + } + + public Long getSizeBytes() { + return sizeBytes; + } + + public String getRetrieveLink() { + return retrieveLink; + } + + public DSpaceObject getParentObject() { + return parentObject; + } + + public CheckSum getCheckSum() { + return checkSum; + } + + public void setCheckSum(CheckSum checkSum) { + this.checkSum = checkSum; + } + +} diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/CheckSum.java b/dspace-rest/src/main/java/org/dspace/rest/common/CheckSum.java new file mode 100644 index 0000000000000000000000000000000000000000..2c716f6b9db9d8bc2c3b10f570c7927dfc4e1e72 --- /dev/null +++ b/dspace-rest/src/main/java/org/dspace/rest/common/CheckSum.java @@ -0,0 +1,39 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +package org.dspace.rest.common; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.XmlValue; + +@XmlType +public class CheckSum{ + String checkSumAlgorithm; + String value; + + public CheckSum(){} + + @XmlAttribute(name="checkSumAlgorithm") + public String getCheckSumAlgorith() { + return checkSumAlgorithm; + } + + public void setCheckSumAlgorith(String checkSumAlgorith) { + this.checkSumAlgorithm = checkSumAlgorith; + } + + @XmlValue + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} \ No newline at end of file diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/Collection.java b/dspace-rest/src/main/java/org/dspace/rest/common/Collection.java new file mode 100644 index 0000000000000000000000000000000000000000..b8e32ab91d9a05920c99daff23070d1c3242a285 --- /dev/null +++ b/dspace-rest/src/main/java/org/dspace/rest/common/Collection.java @@ -0,0 +1,203 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.rest.common; + +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeManager; +import org.dspace.content.ItemIterator; +import org.dspace.core.Context; + +import javax.ws.rs.WebApplicationException; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created with IntelliJ IDEA. + * User: peterdietz + * Date: 5/22/13 + * Time: 9:41 AM + * To change this template use File | Settings | File Templates. + */ +@XmlRootElement(name = "collection") +public class Collection extends DSpaceObject { + Logger log = Logger.getLogger(Collection.class); + + //Relationships + private Bitstream logo; + private Community parentCommunity; + private List<Community> parentCommunityList = new ArrayList<Community>(); + + private List<Item> items = new ArrayList<Item>(); + + //Collection-Metadata + private String license; + private String copyrightText, introductoryText, shortDescription, sidebarText; + + //Calculated + private Integer numberItems; + + public Collection(){} + + public Collection(org.dspace.content.Collection collection, String expand, Context context, Integer limit, Integer offset) throws SQLException, WebApplicationException{ + super(collection); + setup(collection, expand, context, limit, offset); + } + + private void setup(org.dspace.content.Collection collection, String expand, Context context, Integer limit, Integer offset) throws SQLException{ + List<String> expandFields = new ArrayList<String>(); + if(expand != null) { + expandFields = Arrays.asList(expand.split(",")); + } + + this.setCopyrightText(collection.getMetadata(org.dspace.content.Collection.COPYRIGHT_TEXT)); + this.setIntroductoryText(collection.getMetadata(org.dspace.content.Collection.INTRODUCTORY_TEXT)); + this.setShortDescription(collection.getMetadata(org.dspace.content.Collection.SHORT_DESCRIPTION)); + this.setSidebarText(collection.getMetadata(org.dspace.content.Collection.SIDEBAR_TEXT)); + + if(expandFields.contains("parentCommunityList") || expandFields.contains("all")) { + org.dspace.content.Community[] parentCommunities = collection.getCommunities(); + for(org.dspace.content.Community parentCommunity : parentCommunities) { + this.addParentCommunityList(new Community(parentCommunity, null, context)); + } + } else { + this.addExpand("parentCommunityList"); + } + + if(expandFields.contains("parentCommunity") | expandFields.contains("all")) { + org.dspace.content.Community parentCommunity = (org.dspace.content.Community) collection.getParentObject(); + this.setParentCommunity(new Community(parentCommunity, null, context)); + } else { + this.addExpand("parentCommunity"); + } + + //TODO: Item paging. limit, offset/page + if(expandFields.contains("items") || expandFields.contains("all")) { + ItemIterator childItems; + if(limit != null && limit >= 0 && offset != null && offset >= 0) { + childItems = collection.getItems(limit, offset); + } else { + childItems = collection.getItems(); + } + + items = new ArrayList<Item>(); + while(childItems.hasNext()) { + org.dspace.content.Item item = childItems.next(); + if(AuthorizeManager.authorizeActionBoolean(context, item, org.dspace.core.Constants.READ)) { + items.add(new Item(item, null, context)); + } + } + } else { + this.addExpand("items"); + } + + if(expandFields.contains("license") || expandFields.contains("all")) { + setLicense(collection.getLicense()); + } else { + this.addExpand("license"); + } + + if(expandFields.contains("logo") || expandFields.contains("all")) { + if(collection.getLogo() != null) { + this.logo = new Bitstream(collection.getLogo(), null); + } + } + else { + this.addExpand("logo"); + } + + if(!expandFields.contains("all")) { + this.addExpand("all"); + } + + this.setNumberItems(collection.countItems()); + } + + public Bitstream getLogo() { + return logo; + } + + public Integer getNumberItems() { + return numberItems; + } + + public void setNumberItems(Integer numberItems) { + this.numberItems = numberItems; + } + + public Community getParentCommunity() { + return parentCommunity; + } + + public void setParentCommunity(Community parentCommunity) { + this.parentCommunity = parentCommunity; + } + + public List<Item> getItems() { + return items; + } + + public void setItems(List<Item> items) { + this.items = items; + } + + public void setParentCommunityList(List<Community> parentCommunityList) { + this.parentCommunityList = parentCommunityList; + } + + public List<Community> getParentCommunityList() { + return parentCommunityList; + } + + public void addParentCommunityList(Community parentCommunity) { + this.parentCommunityList.add(parentCommunity); + } + + public String getLicense() { + return license; + } + + public void setLicense(String license) { + this.license = license; + } + + public String getCopyrightText() { + return copyrightText; + } + + public void setCopyrightText(String copyrightText) { + this.copyrightText = copyrightText; + } + + public String getIntroductoryText() { + return introductoryText; + } + + public void setIntroductoryText(String introductoryText) { + this.introductoryText = introductoryText; + } + + public String getShortDescription() { + return shortDescription; + } + + public void setShortDescription(String shortDescription) { + this.shortDescription = shortDescription; + } + + public String getSidebarText() { + return sidebarText; + } + + public void setSidebarText(String sidebarText) { + this.sidebarText = sidebarText; + } +} diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/Community.java b/dspace-rest/src/main/java/org/dspace/rest/common/Community.java new file mode 100644 index 0000000000000000000000000000000000000000..1c135610078d3dae6f4f7346ccac5ae9c2568c3f --- /dev/null +++ b/dspace-rest/src/main/java/org/dspace/rest/common/Community.java @@ -0,0 +1,174 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.rest.common; + +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeManager; +import org.dspace.core.Context; + +import javax.ws.rs.WebApplicationException; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created with IntelliJ IDEA. + * User: peterdietz + * Date: 5/22/13 + * Time: 9:41 AM + * To change this template use File | Settings | File Templates. + */ +@XmlRootElement(name = "community") +public class Community extends DSpaceObject{ + private static Logger log = Logger.getLogger(Community.class); + + //Exandable relationships + private Bitstream logo; + + private Community parentCommunity; + + private String copyrightText, introductoryText, shortDescription, sidebarText; + private Integer countItems; + + @XmlElement(name = "subcommunities", required = true) + private List<Community> subCommunities = new ArrayList<Community>(); + + private List<Collection> collections = new ArrayList<Collection>(); + + public Community(){} + + public Community(org.dspace.content.Community community, String expand, Context context) throws SQLException, WebApplicationException{ + super(community); + setup(community, expand, context); + } + + private void setup(org.dspace.content.Community community, String expand, Context context) throws SQLException{ + List<String> expandFields = new ArrayList<String>(); + if(expand != null) { + expandFields = Arrays.asList(expand.split(",")); + } + + this.setCopyrightText(community.getMetadata(org.dspace.content.Community.COPYRIGHT_TEXT)); + this.setIntroductoryText(community.getMetadata(org.dspace.content.Community.INTRODUCTORY_TEXT)); + this.setShortDescription(community.getMetadata(org.dspace.content.Community.SHORT_DESCRIPTION)); + this.setSidebarText(community.getMetadata(org.dspace.content.Community.SIDEBAR_TEXT)); + this.setCountItems(community.countItems()); + + if(expandFields.contains("parentCommunity") || expandFields.contains("all")) { + org.dspace.content.Community parentCommunity = community.getParentCommunity(); + if(parentCommunity != null) { + setParentCommunity(new Community(parentCommunity, null, context)); + } + } else { + this.addExpand("parentCommunity"); + } + + if(expandFields.contains("collections") || expandFields.contains("all")) { + org.dspace.content.Collection[] collectionArray = community.getCollections(); + collections = new ArrayList<Collection>(); + for(org.dspace.content.Collection collection : collectionArray) { + if(AuthorizeManager.authorizeActionBoolean(context, collection, org.dspace.core.Constants.READ)) { + collections.add(new Collection(collection, null, context, null, null)); + } else { + log.info("Omitted restricted collection: " + collection.getID() + " _ " + collection.getName()); + } + } + } else { + this.addExpand("collections"); + } + + if(expandFields.contains("subCommunities") || expandFields.contains("all")) { + org.dspace.content.Community[] communityArray = community.getSubcommunities(); + subCommunities = new ArrayList<Community>(); + for(org.dspace.content.Community subCommunity : communityArray) { + if(AuthorizeManager.authorizeActionBoolean(context, subCommunity, org.dspace.core.Constants.READ)) { + subCommunities.add(new Community(subCommunity, null, context)); + } else { + log.info("Omitted restricted subCommunity: " + subCommunity.getID() + " _ " + subCommunity.getName()); + } + } + } else { + this.addExpand("subCommunities"); + } + + if(expandFields.contains("logo") || expandFields.contains("all")) { + if(community.getLogo() != null) { + logo = new Bitstream(community.getLogo(), null); + } + } else { + this.addExpand("logo"); + } + + if(!expandFields.contains("all")) { + this.addExpand("all"); + } + } + + public List<Collection> getCollections() { + return collections; + } + + public void setCollections(List<Collection> collections) { + this.collections = collections; + } + + public Integer getCountItems() { + return countItems; + } + + public void setCountItems(Integer countItems) { + this.countItems = countItems; + } + + public String getSidebarText() { + return sidebarText; + } + + public void setSidebarText(String sidebarText) { + this.sidebarText = sidebarText; + } + + public String getShortDescription() { + return shortDescription; + } + + public void setShortDescription(String shortDescription) { + this.shortDescription = shortDescription; + } + + public String getIntroductoryText() { + return introductoryText; + } + + public void setIntroductoryText(String introductoryText) { + this.introductoryText = introductoryText; + } + + public String getCopyrightText() { + return copyrightText; + } + + public void setCopyrightText(String copyrightText) { + this.copyrightText = copyrightText; + } + + public Community getParentCommunity() { + return parentCommunity; + } + + public void setParentCommunity(Community parentCommunity) { + this.parentCommunity = parentCommunity; + } + + public Bitstream getLogo() { + return logo; + } +} diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/DSpaceObject.java b/dspace-rest/src/main/java/org/dspace/rest/common/DSpaceObject.java new file mode 100644 index 0000000000000000000000000000000000000000..864872d606f280207e0a9256059b4dc5d01ea8d2 --- /dev/null +++ b/dspace-rest/src/main/java/org/dspace/rest/common/DSpaceObject.java @@ -0,0 +1,100 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.rest.common; + +import org.atteo.evo.inflector.English; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.ArrayList; +import java.util.List; + +/** + * Created with IntelliJ IDEA. + * User: peterdietz + * Date: 10/7/13 + * Time: 12:11 PM + * To change this template use File | Settings | File Templates. + */ +@XmlRootElement(name = "dspaceobject") +public class DSpaceObject { + private Integer id; + + private String name; + + private String handle; + + private String type; + + @XmlElement(name = "link", required = true) + private String link; + + @XmlElement(required = true) + private ArrayList<String> expand = new ArrayList<String>(); + + public DSpaceObject() { + + } + + public DSpaceObject(org.dspace.content.DSpaceObject dso) { + setID(dso.getID()); + setName(dso.getName()); + setHandle(dso.getHandle()); + setType(dso.getTypeText().toLowerCase()); + } + + public Integer getID() { + return id; + } + + public void setID(Integer id) { + this.id = id; + } + + public String getName(){ + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public String getHandle() { + return handle; + } + + public void setHandle(String handle) { + this.handle = handle; + } + + public String getLink() { + //TODO, get actual contextPath of /rest/ + return "/rest/" + English.plural(getType()) + "/" + getID(); + } + + public String getType() { + return this.type; + } + + public void setType(String type) { + this.type = type; + } + + + public List<String> getExpand() { + return expand; + } + + public void setExpand(ArrayList<String> expand) { + this.expand = expand; + } + + public void addExpand(String expandableAttribute) { + this.expand.add(expandableAttribute); + } +} diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/Item.java b/dspace-rest/src/main/java/org/dspace/rest/common/Item.java new file mode 100644 index 0000000000000000000000000000000000000000..d21ba75cc891c7a7887241d1b3de5273679a2512 --- /dev/null +++ b/dspace-rest/src/main/java/org/dspace/rest/common/Item.java @@ -0,0 +1,189 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.rest.common; + +import org.apache.log4j.Logger; +import org.dspace.app.util.MetadataExposure; +import org.dspace.authorize.AuthorizeManager; +import org.dspace.content.Bundle; +import org.dspace.content.DCValue; +import org.dspace.core.Context; + +import javax.ws.rs.WebApplicationException; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created with IntelliJ IDEA. + * User: peterdietz + * Date: 9/19/13 + * Time: 4:50 PM + * To change this template use File | Settings | File Templates. + */ +@XmlRootElement(name = "item") +public class Item extends DSpaceObject { + Logger log = Logger.getLogger(Item.class); + + String isArchived; + String isWithdrawn; + String lastModified; + + Collection parentCollection; + List<Collection> parentCollectionList; + + List<Community> parentCommunityList; + + List<MetadataEntry> metadata; + + List<Bitstream> bitstreams; + + public Item(){} + + public Item(org.dspace.content.Item item, String expand, Context context) throws SQLException, WebApplicationException{ + super(item); + setup(item, expand, context); + } + + private void setup(org.dspace.content.Item item, String expand, Context context) throws SQLException{ + List<String> expandFields = new ArrayList<String>(); + if(expand != null) { + expandFields = Arrays.asList(expand.split(",")); + } + + if(expandFields.contains("metadata") || expandFields.contains("all")) { + metadata = new ArrayList<MetadataEntry>(); + DCValue[] dcvs = item.getMetadata(org.dspace.content.Item.ANY, org.dspace.content.Item.ANY, org.dspace.content.Item.ANY, org.dspace.content.Item.ANY); + for (DCValue dcv : dcvs) { + if (!MetadataExposure.isHidden(context, dcv.schema, dcv.element, dcv.qualifier)) { + metadata.add(new MetadataEntry(dcv.getField(), dcv.value)); + } + } + } else { + this.addExpand("metadata"); + } + + this.setArchived(Boolean.toString(item.isArchived())); + this.setWithdrawn(Boolean.toString(item.isWithdrawn())); + this.setLastModified(item.getLastModified().toString()); + + if(expandFields.contains("parentCollection") || expandFields.contains("all")) { + this.parentCollection = new Collection(item.getOwningCollection(), null, context, null, null); + } else { + this.addExpand("parentCollection"); + } + + if(expandFields.contains("parentCollectionList") || expandFields.contains("all")) { + this.parentCollectionList = new ArrayList<Collection>(); + org.dspace.content.Collection[] collections = item.getCollections(); + for(org.dspace.content.Collection collection : collections) { + this.parentCollectionList.add(new Collection(collection, null, context, null, null)); + } + } else { + this.addExpand("parentCollectionList"); + } + + if(expandFields.contains("parentCommunityList") || expandFields.contains("all")) { + this.parentCommunityList = new ArrayList<Community>(); + org.dspace.content.Community[] communities = item.getCommunities(); + for(org.dspace.content.Community community : communities) { + this.parentCommunityList.add(new Community(community, null, context)); + } + } else { + this.addExpand("parentCommunityList"); + } + + //TODO: paging - offset, limit + if(expandFields.contains("bitstreams") || expandFields.contains("all")) { + bitstreams = new ArrayList<Bitstream>(); + Bundle[] bundles = item.getBundles(); + for(Bundle bundle : bundles) { + org.dspace.content.Bitstream[] itemBitstreams = bundle.getBitstreams(); + for(org.dspace.content.Bitstream itemBitstream : itemBitstreams) { + if(AuthorizeManager.authorizeActionBoolean(context, itemBitstream, org.dspace.core.Constants.READ)) { + bitstreams.add(new Bitstream(itemBitstream, null)); + } + } + } + } else { + this.addExpand("bitstreams"); + } + + if(!expandFields.contains("all")) { + this.addExpand("all"); + } + } + + public String getArchived() { + return isArchived; + } + + public void setArchived(String archived) { + isArchived = archived; + } + + public String getWithdrawn() { + return isWithdrawn; + } + + public void setWithdrawn(String withdrawn) { + isWithdrawn = withdrawn; + } + + public String getLastModified() { + return lastModified; + } + + public void setLastModified(String lastModified) { + this.lastModified = lastModified; + } + + public Collection getParentCollection() { + return parentCollection; + } + + public List<Collection> getParentCollectionList() { + return parentCollectionList; + } + + public List<MetadataEntry> getMetadata() { + return metadata; + } + + public List<Bitstream> getBitstreams() { + return bitstreams; + } + + public List<Community> getParentCommunityList() { + return parentCommunityList; + } + + public void setParentCollection(Collection parentCollection) { + this.parentCollection = parentCollection; + } + + public void setParentCollectionList(List<Collection> parentCollectionList) { + this.parentCollectionList = parentCollectionList; + } + + public void setParentCommunityList(List<Community> parentCommunityList) { + this.parentCommunityList = parentCommunityList; + } + + @XmlElement(required = true) + public void setMetadata(List<MetadataEntry> metadata) { + this.metadata = metadata; + } + + public void setBitstreams(List<Bitstream> bitstreams) { + this.bitstreams = bitstreams; + } +} diff --git a/dspace-rest/src/main/java/org/dspace/rest/common/MetadataEntry.java b/dspace-rest/src/main/java/org/dspace/rest/common/MetadataEntry.java new file mode 100644 index 0000000000000000000000000000000000000000..18d28b0eabc525bd795e1c0a6b518fd336e7503d --- /dev/null +++ b/dspace-rest/src/main/java/org/dspace/rest/common/MetadataEntry.java @@ -0,0 +1,46 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.rest.common; + +import javax.xml.bind.annotation.XmlRootElement; + +/** + * Created with IntelliJ IDEA. + * User: peterdietz + * Date: 9/20/13 + * Time: 5:51 PM + * To change this template use File | Settings | File Templates. + */ +@XmlRootElement(name = "metadataentry") +public class MetadataEntry { + String key; + String value; + + public MetadataEntry() {} + + public MetadataEntry(String key, String value) { + this.key = key; + this.value = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } +} diff --git a/dspace-rest/src/main/webapp/WEB-INF/applicationContext.xml b/dspace-rest/src/main/webapp/WEB-INF/applicationContext.xml new file mode 100644 index 0000000000000000000000000000000000000000..0d72338d12051c4f6dac2a7ce1ebf1cf1b7ba2ed --- /dev/null +++ b/dspace-rest/src/main/webapp/WEB-INF/applicationContext.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + The contents of this file are subject to the license and copyright + detailed in the LICENSE and NOTICE files at the root of the source + tree and available online at + + http://www.dspace.org/license/ + +--> +<beans + xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:util="http://www.springframework.org/schema/util" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd + http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"> + + <!-- Acquires the DSpace Utility Class with initialized Service Manager --> + <bean id="dspace" class="org.dspace.utils.DSpace"/> + + <!-- Acquires reference to EventService --> + <bean id="dspace.eventService" factory-bean="dspace" factory-method="getEventService"/> + + <!-- Inject the Default LoggerUsageEventListener into the EventService --> + <bean class="org.dspace.usage.LoggerUsageEventListener"> + <property name="eventService" > + <ref bean="dspace.eventService"/> + </property> + </bean> + + <!-- Inject the Default LoggerUsageEventListener into the EventService --> + <bean class="org.dspace.statistics.SolrLoggerUsageEventListener"> + <property name="eventService" > + <ref bean="dspace.eventService"/> + </property> + </bean> + + <!-- Elastic Search --> + <!--<bean class="org.dspace.statistics.ElasticSearchLoggerEventListener"> + <property name="eventService"> + <ref bean="dspace.eventService" /> + </property> + </bean>--> + + <!-- + Uncomment to enable TabFileUsageEventListener + <bean class="org.dspace.app.statistics.TabFileUsageEventListener"> + <property name="eventService" > + <ref bean="dspace.eventService"/> + </property> + </bean> + --> + + <!-- + Uncomment to enable PassiveUsageEventListener + <bean class="org.dspace.app.statistics.PassiveUsageEventListener"> + <property name="eventService" > + <ref bean="dspace.eventService"/> + </property> + </bean> + --> + +</beans> diff --git a/dspace-rest/src/main/webapp/WEB-INF/web.xml b/dspace-rest/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000000000000000000000000000000000..2167ea94ca5f43ca59504aba1a2b29773e68b7ea --- /dev/null +++ b/dspace-rest/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + The contents of this file are subject to the license and copyright + detailed in the LICENSE and NOTICE files at the root of the source + tree and available online at + + http://www.dspace.org/license/ + +--> +<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://java.sun.com/xml/ns/javaee" + xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" + id="WebApp_ID" version="2.5"> + <servlet> + <servlet-name>DSpace REST API</servlet-name> + <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class> + <init-param> + <!-- + The jersey ServletContainer will look for our Root Resource Class + (i.e. our HelloWorld class) in the foo.bar package + There are other ways to register this; see the jersey documentation for + more details + --> + <param-name>com.sun.jersey.config.property.packages</param-name> + <param-value>org.dspace.rest</param-value> + </init-param> + <init-param> + <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name> + <param-value>true</param-value> + </init-param> + <!-- + Load the ServletContainer at startup. A value of 1 indicates the ServletContainer + is a high priority servlet to load + --> + <load-on-startup>1</load-on-startup> + </servlet> + <servlet-mapping> + <servlet-name>DSpace REST API</servlet-name> + <!-- + The url-pattern can be used to define your URL. + Example, running local host with a context of "hello" and path annotation of "world" + on the HelloWorld class: + + <url-pattern>/*</url-pattern> + The web service will be available at: http://localhost:8080/hello/world + + + <url-pattern>/jersey/*</url-pattern> + The web service will be available at http://localhost:8080/hello/jersey/world + --> + <url-pattern>/*</url-pattern> + </servlet-mapping> + + <!-- DSpace Configuration Information --> + <context-param> + <param-name>dspace-config</param-name> + <param-value>${dspace.dir}/config/dspace.cfg</param-value> + </context-param> + + <!-- new ConfigurationService initialization for dspace.dir --> + <context-param> + <description> + The location of the main DSpace configuration file + </description> + <param-name>dspace.dir</param-name> + <param-value>${dspace.dir}</param-value> + </context-param> + + <context-param> + <param-name>contextConfigLocation</param-name> + <param-value> + /WEB-INF/applicationContext.xml + </param-value> + <!-- + Add this context if using Spring Security + /WEB-INF/applicationContext-security.xml + --> + </context-param> + + <listener> + <listener-class>org.dspace.app.util.DSpaceContextListener</listener-class> + </listener> + + <!-- kernel start listener (from impl) + The following listener can be used instead of the filter below, it is simpler, cleaner + and eliminates the need for a DSpaceKernelServletFilter filter to be involved with the + request cycle. + --> + <listener> + <listener-class>org.dspace.servicemanager.servlet.DSpaceKernelServletContextListener</listener-class> + </listener> + + <listener> + <listener-class> + org.springframework.web.context.ContextLoaderListener + </listener-class> + </listener> + + + +</web-app> diff --git a/dspace-solr/pom.xml b/dspace-solr/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..a2906edb3dfe67661e666702b8721cc1ba1f0a44 --- /dev/null +++ b/dspace-solr/pom.xml @@ -0,0 +1,165 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <!-- + 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. + --> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.dspace</groupId> + <artifactId>dspace-parent</artifactId> + <version>4.1</version> + <relativePath>..</relativePath> + </parent> + + <groupId>org.dspace</groupId> + <artifactId>dspace-solr</artifactId> + <name>Apache Solr Webapp</name> + <description>Apache Solr Server</description> + <packaging>war</packaging> + + <properties> + <lucene.version>4.4.0</lucene.version> + <solr.version>4.4.0</solr.version> + <!-- 'root.basedir' is the path to the root [dspace-src] dir. It must be redefined by each child POM, + as it is used to reference the LICENSE_HEADER and *.properties file(s) in that directory. --> + <root.basedir>${basedir}/..</root.basedir> + </properties> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-war-plugin</artifactId> + <version>2.4</version> + <configuration> + <!-- This 'dspace-solr' WAR overlays the Apache Solr Web Application + available in Maven Central --> + <overlays> + <overlay> + <groupId>org.apache.solr</groupId> + <artifactId>solr</artifactId> + <!-- + Exclude the solr core named apache-solr-core, this is needed because the dspace-solr changes + need to take precendence over the solr-core, the solr-core will still be loaded in the solr-core.jar + --> + <excludes> + <exclude>WEB-INF/lib/apache-solr-core-${solr.version}.jar</exclude> + </excludes> + </overlay> + </overlays> + </configuration> + <executions> + <execution> + <!-- This execution creates a normal WAR (with all JARs, etc)--> + <id>webapp</id> + <configuration> + <primaryArtifact>true</primaryArtifact> + <archiveClasses>true</archiveClasses> + <attachClasses>true</attachClasses> + <classesClassifier>classes</classesClassifier> + <warSourceExcludes>WEB-INF/classes/**</warSourceExcludes> + <packagingExcludes> + WEB-INF/classes/**, + WEB-INF/lib/slf4j-jdk14-*.jar, + WEB-INF/lib/log4j-over-slf4j-*.jar + </packagingExcludes> + </configuration> + <goals> + <goal>war</goal> + </goals> + <phase>package</phase> + </execution> + <execution> + <!-- This execution creates a "skinny" WAR (without any JARs included)--> + <id>skinny</id> + <configuration> + <primaryArtifact>false</primaryArtifact> + <classifier>skinny</classifier> + <warSourceExcludes>WEB-INF/lib/**,WEB-INF/classes/**</warSourceExcludes> + <packagingExcludes>WEB-INF/lib/**,WEB-INF/classes/**</packagingExcludes> + </configuration> + <goals> + <goal>war</goal> + </goals> + <phase>package</phase> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <dependencies> + <!-- Depends on the Apache 'solr' web application (see Overlay settings above)--> + <dependency> + <groupId>org.apache.solr</groupId> + <artifactId>solr</artifactId> + <version>${solr.version}</version> + <type>war</type> + </dependency> + <dependency> + <groupId>org.apache.solr</groupId> + <artifactId>solr-core</artifactId> + <version>${solr.version}</version> + <type>jar</type> + <exclusions> + <exclusion> + <groupId>jdk.tools</groupId> + <artifactId>jdk.tools</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.apache.solr</groupId> + <artifactId>solr-solrj</artifactId> + <version>${solr.version}</version> + </dependency> + <dependency> + <groupId>org.apache.lucene</groupId> + <artifactId>lucene-core</artifactId> + </dependency> + + <!-- Replace J.U.L. logging with log4j --> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jul-to-slf4j</artifactId> + <version>1.6.1</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + <version>1.6.1</version> + <scope>runtime</scope> + </dependency> + <dependency> + <artifactId>log4j</artifactId> + <groupId>log4j</groupId> + <type>jar</type> + <version>1.2.16</version> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + <version>2.5</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + <version>1.1.1</version> + </dependency> + </dependencies> + +</project> diff --git a/dspace-solr/src/main/java/org/apache/solr/handler/component/FacetComponent.java b/dspace-solr/src/main/java/org/apache/solr/handler/component/FacetComponent.java new file mode 100644 index 0000000000000000000000000000000000000000..9ced848b4f8856ca2d51df64a562d8520fb2593c --- /dev/null +++ b/dspace-solr/src/main/java/org/apache/solr/handler/component/FacetComponent.java @@ -0,0 +1,834 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +package org.apache.solr.handler.component; + +import org.apache.lucene.util.OpenBitSet; +import org.apache.solr.common.SolrException; +import org.apache.solr.common.params.CommonParams; +import org.apache.solr.common.params.FacetParams; +import org.apache.solr.common.params.ModifiableSolrParams; +import org.apache.solr.common.params.SolrParams; +import org.apache.solr.common.util.NamedList; +import org.apache.solr.common.util.SimpleOrderedMap; +import org.apache.solr.common.util.StrUtils; +import org.apache.solr.request.SimpleFacets; +import org.apache.solr.schema.FieldType; +import org.apache.solr.search.QueryParsing; +import org.apache.solr.search.SyntaxError; + +import java.io.IOException; +import java.net.URL; +import java.util.*; + +/** + * TODO! + * + * @version $Id: FacetComponent.java 1152531 2011-07-31 00:43:33Z koji $ + * @since solr 1.3 + */ +public class FacetComponent extends SearchComponent +{ + public static final String COMPONENT_NAME = "facet"; + + @Override + public void prepare(ResponseBuilder rb) throws IOException + { + if (rb.req.getParams().getBool(FacetParams.FACET,false)) { + rb.setNeedDocSet( true ); + rb.doFacets = true; + } + } + + /** + * Actually run the query + * @param rb + */ + @Override + public void process(ResponseBuilder rb) throws IOException + { + if (rb.doFacets) { + SolrParams params = rb.req.getParams(); + SimpleFacets f = new SimpleFacets(rb.req, + rb.getResults().docSet, + params, + rb ); + + // TODO ???? add this directly to the response, or to the builder? + rb.rsp.add( "facet_counts", f.getFacetCounts() ); + } + } + + private static final String commandPrefix = "{!" + CommonParams.TERMS + "=$"; + + @Override + public int distributedProcess(ResponseBuilder rb) throws IOException { + if (!rb.doFacets) { + return ResponseBuilder.STAGE_DONE; + } + + if (rb.stage == ResponseBuilder.STAGE_GET_FIELDS) { + // overlap facet refinement requests (those shards that we need a count for + // particular facet values from), where possible, with + // the requests to get fields (because we know that is the + // only other required phase). + // We do this in distributedProcess so we can look at all of the + // requests in the outgoing queue at once. + + + + for (int shardNum=0; shardNum<rb.shards.length; shardNum++) { + List<String> refinements = null; + + for (DistribFieldFacet dff : rb._facetInfo.facets.values()) { + if (!dff.needRefinements) continue; + List<String> refList = dff._toRefine[shardNum]; + if (refList == null || refList.size()==0) continue; + + String key = dff.getKey(); // reuse the same key that was used for the main facet + String termsKey = key + "__terms"; + String termsVal = StrUtils.join(refList, ','); + + String facetCommand; + // add terms into the original facet.field command + // do it via parameter reference to avoid another layer of encoding. + + String termsKeyEncoded = QueryParsing.encodeLocalParamVal(termsKey); + if (dff.localParams != null) { + facetCommand = commandPrefix+termsKeyEncoded + " " + dff.facetStr.substring(2); + } else { + facetCommand = commandPrefix+termsKeyEncoded+'}'+dff.field; + } + + if (refinements == null) { + refinements = new ArrayList<String>(); + } + + refinements.add(facetCommand); + refinements.add(termsKey); + refinements.add(termsVal); + } + + if (refinements == null) continue; + + + String shard = rb.shards[shardNum]; + ShardRequest refine = null; + boolean newRequest = false; + + // try to find a request that is already going out to that shard. + // If nshards becomes to great, we way want to move to hashing for better + // scalability. + for (ShardRequest sreq : rb.outgoing) { + if ((sreq.purpose & ShardRequest.PURPOSE_GET_FIELDS)!=0 + && sreq.shards != null + && sreq.shards.length==1 + && sreq.shards[0].equals(shard)) + { + refine = sreq; + break; + } + } + + if (refine == null) { + // we didn't find any other suitable requests going out to that shard, so + // create one ourselves. + newRequest = true; + refine = new ShardRequest(); + refine.shards = new String[]{rb.shards[shardNum]}; + refine.params = new ModifiableSolrParams(rb.req.getParams()); + // don't request any documents + refine.params.remove(CommonParams.START); + refine.params.set(CommonParams.ROWS,"0"); + } + + refine.purpose |= ShardRequest.PURPOSE_REFINE_FACETS; + refine.params.set(FacetParams.FACET, "true"); + refine.params.remove(FacetParams.FACET_FIELD); + refine.params.remove(FacetParams.FACET_QUERY); + + for (int i=0; i<refinements.size();) { + String facetCommand=refinements.get(i++); + String termsKey=refinements.get(i++); + String termsVal=refinements.get(i++); + + refine.params.add(FacetParams.FACET_FIELD, facetCommand); + refine.params.set(termsKey, termsVal); + } + + if (newRequest) { + rb.addRequest(this, refine); + } + } + } + + return ResponseBuilder.STAGE_DONE; + } + + @Override + public void modifyRequest(ResponseBuilder rb, SearchComponent who, ShardRequest sreq) { + if (!rb.doFacets) return; + + if ((sreq.purpose & ShardRequest.PURPOSE_GET_TOP_IDS) != 0) { + sreq.purpose |= ShardRequest.PURPOSE_GET_FACETS; + + FacetInfo fi = rb._facetInfo; + if (fi == null) { + rb._facetInfo = fi = new FacetInfo(); + fi.parse(rb.req.getParams(), rb); + // should already be true... + // sreq.params.set(FacetParams.FACET, "true"); + } + + sreq.params.remove(FacetParams.FACET_MINCOUNT); + sreq.params.remove(FacetParams.FACET_OFFSET); + sreq.params.remove(FacetParams.FACET_LIMIT); + + for (DistribFieldFacet dff : fi.facets.values()) { + String paramStart = "f." + dff.field + '.'; + sreq.params.remove(paramStart + FacetParams.FACET_MINCOUNT); + sreq.params.remove(paramStart + FacetParams.FACET_OFFSET); + + dff.initialLimit = dff.limit <= 0 ? dff.limit : dff.offset + dff.limit; + + if (dff.sort.equals(FacetParams.FACET_SORT_COUNT)) { + if (dff.limit > 0) { + // set the initial limit higher to increase accuracy + dff.initialLimit = (int)(dff.initialLimit * 1.5) + 10; + dff.initialMincount = 0; // TODO: we could change this to 1, but would then need more refinement for small facet result sets? + } else { + // if limit==-1, then no need to artificially lower mincount to 0 if it's 1 + dff.initialMincount = Math.min(dff.minCount, 1); + } + } else { + // we're sorting by index order. + // if minCount==0, we should always be able to get accurate results w/o over-requesting or refining + // if minCount==1, we should be able to get accurate results w/o over-requesting, but we'll need to refine + // if minCount==n (>1), we can set the initialMincount to minCount/nShards, rounded up. + // For example, we know that if minCount=10 and we have 3 shards, then at least one shard must have a count of 4 for the term + // For the minCount>1 case, we can generate too short of a list (miss terms at the end of the list) unless limit==-1 + // For example: each shard could produce a list of top 10, but some of those could fail to make it into the combined list (i.e. + // we needed to go beyond the top 10 to generate the top 10 combined). Overrequesting can help a little here, but not as + // much as when sorting by count. + if (dff.minCount <= 1) { + dff.initialMincount = dff.minCount; + } else { + dff.initialMincount = (int)Math.ceil((double)dff.minCount / rb.shards.length); + // dff.initialMincount = 1; + } + } + + if (dff.initialMincount != 0) { + sreq.params.set(paramStart + FacetParams.FACET_MINCOUNT, dff.initialMincount); + } + + // Currently this is for testing only and allows overriding of the + // facet.limit set to the shards + dff.initialLimit = rb.req.getParams().getInt("facet.shard.limit", dff.initialLimit); + + sreq.params.set(paramStart + FacetParams.FACET_LIMIT, dff.initialLimit); + } + } else { + // turn off faceting on other requests + sreq.params.set(FacetParams.FACET, "false"); + // we could optionally remove faceting params + } + } + + @Override + public void handleResponses(ResponseBuilder rb, ShardRequest sreq) { + if (!rb.doFacets) return; + + if ((sreq.purpose & ShardRequest.PURPOSE_GET_FACETS)!=0) { + countFacets(rb, sreq); + } else if ((sreq.purpose & ShardRequest.PURPOSE_REFINE_FACETS)!=0) { + refineFacets(rb, sreq); + } + } + + + + + private void countFacets(ResponseBuilder rb, ShardRequest sreq) { + FacetInfo fi = rb._facetInfo; + + for (ShardResponse srsp: sreq.responses) { + int shardNum = rb.getShardNum(srsp.getShard()); + NamedList facet_counts = (NamedList)srsp.getSolrResponse().getResponse().get("facet_counts"); + + // handle facet queries + NamedList facet_queries = (NamedList)facet_counts.get("facet_queries"); + if (facet_queries != null) { + for (int i=0; i<facet_queries.size(); i++) { + String returnedKey = facet_queries.getName(i); + long count = ((Number)facet_queries.getVal(i)).longValue(); + QueryFacet qf = fi.queryFacets.get(returnedKey); + qf.count += count; + } + } + + // step through each facet.field, adding results from this shard + NamedList facet_fields = (NamedList)facet_counts.get("facet_fields"); + + if (facet_fields != null) { + for (DistribFieldFacet dff : fi.facets.values()) { + dff.add(shardNum, (NamedList)facet_fields.get(dff.getKey()), dff.initialLimit); + } + } + + // Distributed facet_dates + // + // The implementation below uses the first encountered shard's + // facet_dates as the basis for subsequent shards' data to be merged. + // (the "NOW" param should ensure consistency) + @SuppressWarnings("unchecked") + SimpleOrderedMap<SimpleOrderedMap<Object>> facet_dates = + (SimpleOrderedMap<SimpleOrderedMap<Object>>) + facet_counts.get("facet_dates"); + + if (facet_dates != null) { + + // go through each facet_date + for (Map.Entry<String,SimpleOrderedMap<Object>> entry : facet_dates) { + final String field = entry.getKey(); + if (fi.dateFacets.get(field) == null) { + // first time we've seen this field, no merging + fi.dateFacets.add(field, entry.getValue()); + + } else { + // not the first time, merge current field + + SimpleOrderedMap<Object> shardFieldValues + = entry.getValue(); + SimpleOrderedMap<Object> existFieldValues + = fi.dateFacets.get(field); + + for (Map.Entry<String,Object> existPair : existFieldValues) { + final String key = existPair.getKey(); + if (key.equals("gap") || + key.equals("end") || + key.equals("start")) { + // we can skip these, must all be the same across shards + continue; + } + // can be null if inconsistencies in shards responses + Integer newValue = (Integer) shardFieldValues.get(key); + if (null != newValue) { + Integer oldValue = ((Integer) existPair.getValue()); + existPair.setValue(oldValue + newValue); + } + } + } + } + } + + // Distributed facet_ranges + // + // The implementation below uses the first encountered shard's + // facet_ranges as the basis for subsequent shards' data to be merged. + @SuppressWarnings("unchecked") + SimpleOrderedMap<SimpleOrderedMap<Object>> facet_ranges = + (SimpleOrderedMap<SimpleOrderedMap<Object>>) + facet_counts.get("facet_ranges"); + + if (facet_ranges != null) { + + // go through each facet_range + for (Map.Entry<String,SimpleOrderedMap<Object>> entry : facet_ranges) { + final String field = entry.getKey(); + if (fi.rangeFacets.get(field) == null) { + // first time we've seen this field, no merging + fi.rangeFacets.add(field, entry.getValue()); + + } else { + // not the first time, merge current field counts + + @SuppressWarnings("unchecked") + NamedList<Integer> shardFieldValues + = (NamedList<Integer>) entry.getValue().get("counts"); + + @SuppressWarnings("unchecked") + NamedList<Integer> existFieldValues + = (NamedList<Integer>) fi.rangeFacets.get(field).get("counts"); + + for (Map.Entry<String,Integer> existPair : existFieldValues) { + final String key = existPair.getKey(); + // can be null if inconsistencies in shards responses + Integer newValue = shardFieldValues.get(key); + if (null != newValue) { + Integer oldValue = existPair.getValue(); + existPair.setValue(oldValue + newValue); + } + } + } + } + } + } + + + // + // This code currently assumes that there will be only a single + // request ((with responses from all shards) sent out to get facets... + // otherwise we would need to wait until all facet responses were received. + // + + for (DistribFieldFacet dff : fi.facets.values()) { + // no need to check these facets for refinement + if (dff.initialLimit <= 0 && dff.initialMincount == 0) continue; + + // only other case where index-sort doesn't need refinement is if minCount==0 + if (dff.minCount == 0 && dff.sort.equals(FacetParams.FACET_SORT_INDEX)) continue; + + @SuppressWarnings("unchecked") // generic array's are annoying + List<String>[] tmp = (List<String>[]) new List[rb.shards.length]; + dff._toRefine = tmp; + + ShardFacetCount[] counts = dff.getCountSorted(); + int ntop = Math.min(counts.length, dff.limit >= 0 ? dff.offset + dff.limit : Integer.MAX_VALUE); + long smallestCount = counts.length == 0 ? 0 : counts[ntop-1].count; + + for (int i=0; i<counts.length; i++) { + ShardFacetCount sfc = counts[i]; + boolean needRefinement = false; + + if (i<ntop) { + // automatically flag the top values for refinement + // this should always be true for facet.sort=index + needRefinement = true; + } else { + // this logic should only be invoked for facet.sort=index (for now) + + // calculate the maximum value that this term may have + // and if it is >= smallestCount, then flag for refinement + long maxCount = sfc.count; + for (int shardNum=0; shardNum<rb.shards.length; shardNum++) { + OpenBitSet obs = dff.counted[shardNum]; + if (!obs.get(sfc.termNum)) { + // if missing from this shard, add the max it could be + maxCount += dff.maxPossible(sfc,shardNum); + } + } + if (maxCount >= smallestCount) { + // TODO: on a tie, we could check the term values + needRefinement = true; + } + } + + if (needRefinement) { + // add a query for each shard missing the term that needs refinement + for (int shardNum=0; shardNum<rb.shards.length; shardNum++) { + OpenBitSet obs = dff.counted[shardNum]; + if (!obs.get(sfc.termNum) && dff.maxPossible(sfc,shardNum)>0) { + dff.needRefinements = true; + List<String> lst = dff._toRefine[shardNum]; + if (lst == null) { + lst = dff._toRefine[shardNum] = new ArrayList<String>(); + } + lst.add(sfc.name); + } + } + } + } + } + } + + + private void refineFacets(ResponseBuilder rb, ShardRequest sreq) { + FacetInfo fi = rb._facetInfo; + + for (ShardResponse srsp: sreq.responses) { + // int shardNum = rb.getShardNum(srsp.shard); + NamedList facet_counts = (NamedList)srsp.getSolrResponse().getResponse().get("facet_counts"); + NamedList facet_fields = (NamedList)facet_counts.get("facet_fields"); + + if (facet_fields == null) continue; // this can happen when there's an exception + + for (int i=0; i<facet_fields.size(); i++) { + String key = facet_fields.getName(i); + DistribFieldFacet dff = fi.facets.get(key); + if (dff == null) continue; + + NamedList shardCounts = (NamedList)facet_fields.getVal(i); + + for (int j=0; j<shardCounts.size(); j++) { + String name = shardCounts.getName(j); + long count = ((Number)shardCounts.getVal(j)).longValue(); + ShardFacetCount sfc = dff.counts.get(name); + sfc.count += count; + } + } + } + } + + @Override + public void finishStage(ResponseBuilder rb) { + if (!rb.doFacets || rb.stage != ResponseBuilder.STAGE_GET_FIELDS) return; + // wait until STAGE_GET_FIELDS + // so that "result" is already stored in the response (for aesthetics) + + + FacetInfo fi = rb._facetInfo; + + NamedList<Object> facet_counts = new SimpleOrderedMap<Object>(); + + NamedList facet_queries = new SimpleOrderedMap(); + facet_counts.add("facet_queries",facet_queries); + for (QueryFacet qf : fi.queryFacets.values()) { + facet_queries.add(qf.getKey(), num(qf.count)); + } + + NamedList<Object> facet_fields = new SimpleOrderedMap<Object>(); + facet_counts.add("facet_fields", facet_fields); + + for (DistribFieldFacet dff : fi.facets.values()) { + NamedList<Object> fieldCounts = new NamedList<Object>(); // order is more important for facets + facet_fields.add(dff.getKey(), fieldCounts); + + ShardFacetCount[] counts; + boolean countSorted = dff.sort.equals(FacetParams.FACET_SORT_COUNT); + if (countSorted) { + counts = dff.countSorted; + if (counts == null || dff.needRefinements) { + counts = dff.getCountSorted(); + } + } else if (dff.sort.equals(FacetParams.FACET_SORT_INDEX)) { + counts = dff.getLexSorted(); + } else { // TODO: log error or throw exception? + counts = dff.getLexSorted(); + } + + if (countSorted) { + int end = dff.limit < 0 ? counts.length : Math.min(dff.offset + dff.limit, counts.length); + for (int i=dff.offset; i<end; i++) { + if (counts[i].count < dff.minCount) { + break; + } + fieldCounts.add(counts[i].name, num(counts[i].count)); + } + } else { + int off = dff.offset; + int lim = dff.limit >= 0 ? dff.limit : Integer.MAX_VALUE; + + // index order... + for (int i=0; i<counts.length; i++) { + long count = counts[i].count; + if (count < dff.minCount) continue; + if (off > 0) { + off--; + continue; + } + if (lim <= 0) { + break; + } + lim--; + fieldCounts.add(counts[i].name, num(count)); + } + } + + if (dff.missing) { + fieldCounts.add(null, num(dff.missingCount)); + } + } + + facet_counts.add("facet_dates", fi.dateFacets); + facet_counts.add("facet_ranges", fi.rangeFacets); + + rb.rsp.add("facet_counts", facet_counts); + + rb._facetInfo = null; // could be big, so release asap + } + + + // use <int> tags for smaller facet counts (better back compatibility) + private Number num(long val) { + if (val < Integer.MAX_VALUE) return (int)val; + else return val; + } + private Number num(Long val) { + if (val.longValue() < Integer.MAX_VALUE) return val.intValue(); + else return val; + } + + + ///////////////////////////////////////////// + /// SolrInfoMBean + //////////////////////////////////////////// + + @Override + public String getDescription() { + return "Handle Faceting"; + } + + @Override + public String getVersion() { + return "$Revision: 1152531 $"; + } + + + public String getSourceId() { + return "$Id: FacetComponent.java 1152531 2011-07-31 00:43:33Z koji $"; + } + + @Override + public String getSource() { + return "$URL: http://svn.apache.org/repos/asf/lucene/dev/tags/lucene_solr_3_5_0/solr/core/src/java/org/apache/solr/handler/component/FacetComponent.java $"; + } + + @Override + public URL[] getDocs() { + return null; + } + + /** + * <b>This API is experimental and subject to change</b> + */ + public static class FacetInfo { + public LinkedHashMap<String,QueryFacet> queryFacets; + public LinkedHashMap<String,DistribFieldFacet> facets; + public SimpleOrderedMap<SimpleOrderedMap<Object>> dateFacets + = new SimpleOrderedMap<SimpleOrderedMap<Object>>(); + public SimpleOrderedMap<SimpleOrderedMap<Object>> rangeFacets + = new SimpleOrderedMap<SimpleOrderedMap<Object>>(); + + public List exceptionList; + + void parse(SolrParams params, ResponseBuilder rb) { + queryFacets = new LinkedHashMap<String,QueryFacet>(); + facets = new LinkedHashMap<String,DistribFieldFacet>(); + + String[] facetQs = params.getParams(FacetParams.FACET_QUERY); + if (facetQs != null) { + for (String query : facetQs) { + QueryFacet queryFacet = new QueryFacet(rb, query); + queryFacets.put(queryFacet.getKey(), queryFacet); + } + } + + String[] facetFs = params.getParams(FacetParams.FACET_FIELD); + if (facetFs != null) { + + for (String field : facetFs) { + DistribFieldFacet ff = new DistribFieldFacet(rb, field); + facets.put(ff.getKey(), ff); + } + } + } + } + + /** + * <b>This API is experimental and subject to change</b> + */ + public static class FacetBase { + String facetType; // facet.field, facet.query, etc (make enum?) + String facetStr; // original parameter value of facetStr + String facetOn; // the field or query, absent localParams if appropriate + private String key; // label in the response for the result... "foo" for {!key=foo}myfield + SolrParams localParams; // any local params for the facet + + public FacetBase(ResponseBuilder rb, String facetType, String facetStr) { + this.facetType = facetType; + this.facetStr = facetStr; + try + { + this.localParams = QueryParsing.getLocalParams(facetStr, + rb.req.getParams()); + } + catch (SyntaxError e) + { + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e); + } + this.facetOn = facetStr; + this.key = facetStr; + + if (localParams != null) { + // remove local params unless it's a query + if (!facetType.equals(FacetParams.FACET_QUERY)) { + facetOn = localParams.get(CommonParams.VALUE); + key = facetOn; + } + + key = localParams.get(CommonParams.OUTPUT_KEY, key); + } + } + + /** returns the key in the response that this facet will be under */ + public String getKey() { return key; } + public String getType() { return facetType; } + } + + /** + * <b>This API is experimental and subject to change</b> + */ + public static class QueryFacet extends FacetBase { + public long count; + + public QueryFacet(ResponseBuilder rb, String facetStr) { + super(rb, FacetParams.FACET_QUERY, facetStr); + } + } + + /** + * <b>This API is experimental and subject to change</b> + */ + public static class FieldFacet extends FacetBase { + public String field; // the field to facet on... "myfield" for {!key=foo}myfield + public FieldType ftype; + public int offset; + public int limit; + public int minCount; + public String sort; + public boolean missing; + public String prefix; + public long missingCount; + + public FieldFacet(ResponseBuilder rb, String facetStr) { + super(rb, FacetParams.FACET_FIELD, facetStr); + fillParams(rb, rb.req.getParams(), facetOn); + } + + private void fillParams(ResponseBuilder rb, SolrParams params, String field) { + this.field = field; + this.ftype = rb.req.getSchema().getFieldTypeNoEx(this.field); + this.offset = params.getFieldInt(field, FacetParams.FACET_OFFSET, 0); + this.limit = params.getFieldInt(field, FacetParams.FACET_LIMIT, 100); + Integer mincount = params.getFieldInt(field, FacetParams.FACET_MINCOUNT); + if (mincount==null) { + Boolean zeros = params.getFieldBool(field, FacetParams.FACET_ZEROS); + // mincount = (zeros!=null && zeros) ? 0 : 1; + mincount = (zeros!=null && !zeros) ? 1 : 0; + // current default is to include zeros. + } + this.minCount = mincount; + this.missing = params.getFieldBool(field, FacetParams.FACET_MISSING, false); + // default to sorting by count if there is a limit. + this.sort = params.getFieldParam(field, FacetParams.FACET_SORT, limit>0 ? FacetParams.FACET_SORT_COUNT : FacetParams.FACET_SORT_INDEX); + if (this.sort.equals(FacetParams.FACET_SORT_COUNT_LEGACY)) { + this.sort = FacetParams.FACET_SORT_COUNT; + } else if (this.sort.equals(FacetParams.FACET_SORT_INDEX_LEGACY)) { + this.sort = FacetParams.FACET_SORT_INDEX; + } + this.prefix = params.getFieldParam(field,FacetParams.FACET_PREFIX); + } + } + + /** + * <b>This API is experimental and subject to change</b> + */ + public static class DistribFieldFacet extends FieldFacet { + public List<String>[] _toRefine; // a List<String> of refinements needed, one for each shard. + + // SchemaField sf; // currently unneeded + + // the max possible count for a term appearing on no list + public long missingMaxPossible; + // the max possible count for a missing term for each shard (indexed by shardNum) + public long[] missingMax; + public OpenBitSet[] counted; // a bitset for each shard, keeping track of which terms seen + public HashMap<String,ShardFacetCount> counts = new HashMap<String,ShardFacetCount>(128); + public int termNum; + + public int initialLimit; // how many terms requested in first phase + public int initialMincount; // mincount param sent to each shard + public boolean needRefinements; + public ShardFacetCount[] countSorted; + + DistribFieldFacet(ResponseBuilder rb, String facetStr) { + super(rb, facetStr); + // sf = rb.req.getSchema().getField(field); + missingMax = new long[rb.shards.length]; + counted = new OpenBitSet[rb.shards.length]; + } + + void add(int shardNum, NamedList shardCounts, int numRequested) { + // shardCounts could be null if there was an exception + int sz = shardCounts == null ? 0 : shardCounts.size(); + int numReceived = sz; + + OpenBitSet terms = new OpenBitSet(termNum+sz); + + long last = 0; + for (int i=0; i<sz; i++) { + String name = shardCounts.getName(i); + long count = ((Number)shardCounts.getVal(i)).longValue(); + if (name == null) { + missingCount += count; + numReceived--; + } else { + ShardFacetCount sfc = counts.get(name); + if (sfc == null) { + sfc = new ShardFacetCount(); + sfc.name = name; + sfc.indexed = ftype == null ? sfc.name : ftype.toInternal(sfc.name); + sfc.termNum = termNum++; + counts.put(name, sfc); + } + sfc.count += count; + terms.fastSet(sfc.termNum); + last = count; + } + } + + // the largest possible missing term is initialMincount if we received less + // than the number requested. + if (numRequested<0 || numRequested != 0 && numReceived < numRequested) { + last = initialMincount; + } + + missingMaxPossible += last; + missingMax[shardNum] = last; + counted[shardNum] = terms; + } + + public ShardFacetCount[] getLexSorted() { + ShardFacetCount[] arr = counts.values().toArray(new ShardFacetCount[counts.size()]); + Arrays.sort(arr, new Comparator<ShardFacetCount>() { + public int compare(ShardFacetCount o1, ShardFacetCount o2) { + return o1.indexed.compareTo(o2.indexed); + } + }); + countSorted = arr; + return arr; + } + + public ShardFacetCount[] getCountSorted() { + ShardFacetCount[] arr = counts.values().toArray(new ShardFacetCount[counts.size()]); + Arrays.sort(arr, new Comparator<ShardFacetCount>() { + public int compare(ShardFacetCount o1, ShardFacetCount o2) { + if (o2.count < o1.count) return -1; + else if (o1.count < o2.count) return 1; + return o1.indexed.compareTo(o2.indexed); + } + }); + countSorted = arr; + return arr; + } + + // returns the max possible value this ShardFacetCount could have for this shard + // (assumes the shard did not report a count for this value) + long maxPossible(ShardFacetCount sfc, int shardNum) { + return missingMax[shardNum]; + // TODO: could store the last term in the shard to tell if this term + // comes before or after it. If it comes before, we could subtract 1 + } + } + + /** + * <b>This API is experimental and subject to change</b> + */ + public static class ShardFacetCount { + public String name; + public String indexed; // the indexed form of the name... used for comparisons. + public long count; + public int termNum; // term number starting at 0 (used in bit arrays) + + @Override + public String toString() { + return "{term="+name+",termNum="+termNum+",count="+count+"}"; + } + } +} diff --git a/dspace-solr/src/main/java/org/dspace/solr/filters/ConfigureLog4jListener.java b/dspace-solr/src/main/java/org/dspace/solr/filters/ConfigureLog4jListener.java new file mode 100644 index 0000000000000000000000000000000000000000..9d87ac27ff7348535a1b773142492788fe4475c3 --- /dev/null +++ b/dspace-solr/src/main/java/org/dspace/solr/filters/ConfigureLog4jListener.java @@ -0,0 +1,87 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +package org.dspace.solr.filters; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import org.apache.log4j.Hierarchy; +import org.apache.log4j.Level; +import org.apache.log4j.PropertyConfigurator; +import org.apache.log4j.helpers.Loader; +import org.apache.log4j.spi.Configurator; +import org.apache.log4j.spi.RootLogger; +import org.apache.log4j.xml.DOMConfigurator; + +/** + * Initialize Log4J at application startup. + * This class mimics the default Log4J initialization procedure, except + * that it is controlled by context parameters rather than system properties. + * + * @author Mark H. Wood + */ +public class ConfigureLog4jListener + implements ServletContextListener +{ + public void contextInitialized(ServletContextEvent sce) + { + ServletContext ctx = sce.getServletContext(); + + String logConfig = ctx.getInitParameter("log4j.configuration"); + if (null == logConfig) + logConfig = "log4j.properties"; + + URL configURL; + try { + configURL = new File(logConfig).toURI().toURL(); + } catch (MalformedURLException e) { + configURL = Loader.getResource(logConfig); + } + + if (null == configURL) + { + ctx.log("Log4J configuration not found. Left unconfigured."); + return; + } + else + { + ctx.log(" In context " + ctx.getContextPath() + + ", configuring Log4J from " + configURL.toExternalForm()); + + String configuratorName = ctx.getInitParameter("log4j.configuratorClass"); + if (null != configuratorName) + { + Configurator configurator; + try + { + configurator = (Configurator) Class.forName(configuratorName).newInstance(); + } catch (Exception ex) + { + ctx.log("Unable to load custom Log4J configuration class '" + + configuratorName + "': " + ex.getMessage()); + return; + } + + configurator.doConfigure(configURL, new Hierarchy(new RootLogger(Level.OFF))); + } + else if (configURL.getFile().endsWith(".xml")) + DOMConfigurator.configure(configURL); + else + PropertyConfigurator.configure(configURL); + } + } + + public void contextDestroyed(ServletContextEvent sce) + { + // Nothing to be done + } +} diff --git a/dspace-solr/src/main/java/org/dspace/solr/filters/LocalHostRestrictionFilter.java b/dspace-solr/src/main/java/org/dspace/solr/filters/LocalHostRestrictionFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..723aee5313e2f54575e3544c138739104b110df4 --- /dev/null +++ b/dspace-solr/src/main/java/org/dspace/solr/filters/LocalHostRestrictionFilter.java @@ -0,0 +1,65 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.solr.filters; + +import java.io.IOException; +import java.net.InetAddress; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +public class LocalHostRestrictionFilter implements Filter { + + private boolean enabled = true; + + public LocalHostRestrictionFilter() { + // TODO Auto-generated constructor stub + } + + public void destroy() { + // TODO Auto-generated method stub + + } + + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + + if(enabled){ + InetAddress ia = InetAddress.getLocalHost(); + String localAddr = ia.getHostAddress(); + String remoteAddr = request.getRemoteAddr(); + + if(!(localAddr.equals(remoteAddr) || remoteAddr.equals("127.0.0.1") || remoteAddr.startsWith("0:0:0:0:0:0:0:1"))) + { + ((HttpServletResponse)response).sendError(403); + return; + } + + } + + chain.doFilter(request, response); + } + + /** + * + */ + public void init(FilterConfig arg0) throws ServletException { + String restrict = arg0.getServletContext().getInitParameter("LocalHostRestrictionFilter.localhost"); + if("false".equalsIgnoreCase(restrict)) + { + enabled = false; + } + + } + +} diff --git a/dspace-solr/src/main/webapp/WEB-INF/web.xml b/dspace-solr/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000000000000000000000000000000000..174d275728302d5c0856ff70bd1b6007c5f6a22b --- /dev/null +++ b/dspace-solr/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,203 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> +<!-- + + The contents of this file are subject to the license and copyright + detailed in the LICENSE and NOTICE files at the root of the source + tree and available online at + + http://www.dspace.org/license/ + +--> + +<web-app> + + <!-- Uncomment if you are trying to use a Resin version before 3.0.19. + Their XML implementation isn't entirely compatible with Xerces. + Below are the implementations to use with Sun's JVM. + <system-property javax.xml.xpath.XPathFactory= + "com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl"/> + <system-property javax.xml.parsers.DocumentBuilderFactory= + "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl"/> + <system-property javax.xml.parsers.SAXParserFactory= + "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"/> + --> + + <!-- People who want to hardcode their "Solr Home" directly into the + WAR File can set the JNDI property here... + --> + <!-- + <env-entry> + <env-entry-name>solr/home</env-entry-name> + <env-entry-value>/put/your/solr/home/here</env-entry-value> + <env-entry-type>java.lang.String</env-entry-type> + </env-entry> + --> + + <context-param> + <param-name>log4j.configuration</param-name> + <param-value>${dspace.dir}/config/log4j-solr.properties</param-value> + <description>URL locating a Log4J configuration file (properties or XML).</description> + </context-param> + + <!-- Any path (name) registered in solrconfig.xml will be sent to that filter --> + <filter> + <filter-name>LocalHostRestrictionFilter</filter-name> + <filter-class>org.dspace.solr.filters.LocalHostRestrictionFilter</filter-class> + </filter> + + <!-- Any path (name) registered in solrconfig.xml will be sent to that filter --> + <filter> + <filter-name>SolrRequestFilter</filter-name> + <filter-class>org.apache.solr.servlet.SolrDispatchFilter</filter-class> + <!-- If you are wiring Solr into a larger web application which controls + the web context root, you will probably want to mount Solr under + a path prefix (app.war with /app/solr mounted into it, for example). + You will need to put this prefix in front of the SolrDispatchFilter + url-pattern mapping too (/solr/*), and also on any paths for + legacy Solr servlet mappings you may be using. + For the Admin UI to work properly in a path-prefixed configuration, + the admin folder containing the resources needs to be under the app context root + named to match the path-prefix. For example: + + .war + xxx + js + main.js + --> + <!-- + <init-param> + <param-name>path-prefix</param-name> + <param-value>/xxx</param-value> + </init-param> + --> + </filter> + + + <filter-mapping> + <filter-name>LocalHostRestrictionFilter</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> + + <filter-mapping> + <!-- + NOTE: When using multicore, /admin JSP URLs with a core specified + such as /solr/coreName/admin/stats.jsp get forwarded by a + RequestDispatcher to /solr/admin/stats.jsp with the specified core + put into request scope keyed as "org.apache.solr.SolrCore". + + It is unnecessary, and potentially problematic, to have the SolrDispatchFilter + configured to also filter on forwards. Do not configure + this dispatcher as <dispatcher>FORWARD</dispatcher>. + --> + <filter-name>SolrRequestFilter</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> + + <!-- Otherwise it will continue to the old servlets --> + + <listener> + <listener-class>org.dspace.solr.filters.ConfigureLog4jListener</listener-class> + </listener> + + <servlet> + <servlet-name>Zookeeper</servlet-name> + <servlet-class>org.apache.solr.servlet.ZookeeperInfoServlet</servlet-class> + </servlet> + + <servlet> + <servlet-name>LoadAdminUI</servlet-name> + <servlet-class>org.apache.solr.servlet.LoadAdminUiServlet</servlet-class> + </servlet> + + <!-- Remove in Solr 5.0 --> + <!-- This sends SC_MOVED_PERMANENTLY (301) for resources that changed in 4.0 --> + <servlet> + <servlet-name>RedirectOldAdminUI</servlet-name> + <servlet-class>org.apache.solr.servlet.RedirectServlet</servlet-class> + <init-param> + <param-name>destination</param-name> + <param-value>${context}/#/</param-value> + </init-param> + </servlet> + + <servlet> + <servlet-name>RedirectOldZookeeper</servlet-name> + <servlet-class>org.apache.solr.servlet.RedirectServlet</servlet-class> + <init-param> + <param-name>destination</param-name> + <param-value>${context}/zookeeper</param-value> + </init-param> + </servlet> + + <servlet> + <servlet-name>RedirectLogging</servlet-name> + <servlet-class>org.apache.solr.servlet.RedirectServlet</servlet-class> + <init-param> + <param-name>destination</param-name> + <param-value>${context}/#/~logging</param-value> + </init-param> + </servlet> + + <servlet> + <servlet-name>SolrRestApi</servlet-name> + <servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class> + <init-param> + <param-name>org.restlet.application</param-name> + <param-value>org.apache.solr.rest.SolrRestApi</param-value> + </init-param> + </servlet> + + <servlet-mapping> + <servlet-name>RedirectOldAdminUI</servlet-name> + <url-pattern>/admin/</url-pattern> + </servlet-mapping> + <servlet-mapping> + <servlet-name>RedirectOldAdminUI</servlet-name> + <url-pattern>/admin</url-pattern> + </servlet-mapping> + <servlet-mapping> + <servlet-name>RedirectOldZookeeper</servlet-name> + <url-pattern>/zookeeper.jsp</url-pattern> + </servlet-mapping> + <servlet-mapping> + <servlet-name>RedirectLogging</servlet-name> + <url-pattern>/logging</url-pattern> + </servlet-mapping> + + <!-- Servlet Mapping --> + <servlet-mapping> + <servlet-name>Zookeeper</servlet-name> + <url-pattern>/zookeeper</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>LoadAdminUI</servlet-name> + <url-pattern>/admin.html</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>SolrRestApi</servlet-name> + <url-pattern>/schema/*</url-pattern> + </servlet-mapping> + + <mime-mapping> + <extension>.xsl</extension> + <!-- per http://www.w3.org/TR/2006/PR-xslt20-20061121/ --> + <mime-type>application/xslt+xml</mime-type> + </mime-mapping> + + <welcome-file-list> + <welcome-file>admin.html</welcome-file> + </welcome-file-list> + + <!-- People who want to hardcode their "Solr Home" directly into the + WAR File can set the JNDI property here... + --> + <env-entry> + <env-entry-name>solr/home</env-entry-name> + <env-entry-value>${dspace.dir}/solr</env-entry-value> + <env-entry-type>java.lang.String</env-entry-type> + </env-entry> + +</web-app> diff --git a/participatorio-utils/admin_scripts-crontab/create-permission_dspace_logs.sh b/participatorio-utils/admin_scripts-crontab/create-permission_dspace_logs.sh new file mode 100644 index 0000000000000000000000000000000000000000..ef8a90d2f6115462cac41fa5b2c921bc0dc97a0f --- /dev/null +++ b/participatorio-utils/admin_scripts-crontab/create-permission_dspace_logs.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +DSPACE_HOME="/home/dspace/webapp" +NEXT_DAY_DATE=$( date --date="tomorrow" +%Y-%m-%d ) + +OWNER="dspace:tomcat7" + +COCOON_LOG="${DSPACE_HOME}/log/cocoon.log.${NEXT_DAY_DATE}" +SOLR_LOG="${DSPACE_HOME}/log/solr.log.${NEXT_DAY_DATE}" +CHECKER_LOG="${DSPACE_HOME}/log/checker.log.${NEXT_DAY_DATE}" +DSPACE_LOG="${DSPACE_HOME}/log/dspace.log.${NEXT_DAY_DATE}" + +touch ${COCOON_LOG} && chown ${OWNER} ${COCOON_LOG} && chmod g+w ${COCOON_LOG} +touch ${SOLR_LOG} && chown ${OWNER} ${SOLR_LOG} && chmod g+w ${SOLR_LOG} +touch ${CHECKER_LOG} && chown ${OWNER} ${CHECKER_LOG} && chmod g+w ${CHECKER_LOG} +touch ${DSPACE_LOG} && chown ${OWNER} ${DSPACE_LOG} && chmod g+w ${DSPACE_LOG} + +exit 0 diff --git a/participatorio-utils/admin_scripts-crontab/dspace_crontab.txt b/participatorio-utils/admin_scripts-crontab/dspace_crontab.txt new file mode 100644 index 0000000000000000000000000000000000000000..afa06f3fbb68b35d5ae6991c7232ec4d7be1f593 --- /dev/null +++ b/participatorio-utils/admin_scripts-crontab/dspace_crontab.txt @@ -0,0 +1,109 @@ +#-------------------------------------------------------------------------------------------------------------- +# BASED ON: +# https://wiki.duraspace.org/display/DSDOC4x/Scheduled+Tasks+via+Cron +# +# HOW TO USE: +# To add it to crontab, execute "$ crontab e" as dspace user and add the following content to the end of file +#-------------------------------------------------------------------------------------------------------------- + +#----------------- +# GLOBAL VARIABLES +#----------------- +# Full path of your local DSpace Installation (e.g. /home/dspace or /dspace or similar) +DSPACE = /home/dspace/webapp + +# Shell to use +SHELL=/bin/sh + +# Add all major 'bin' directories to path +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +# Set JAVA_OPTS with defaults for DSpace Cron Jobs. +# Only provides 512MB of memory by default (which should be enough for most sites). +JAVA_OPTS="-Xmx512M -Xms512M -Dfile.encoding=UTF-8" + +#-------------- +# HOURLY TASKS (Recommended to be run multiple times per day, if possible) +# At a minimum these tasks should be run daily. +#-------------- + +# Regenerate DSpace Sitemaps every 8 hours (12AM, 8AM, 4PM). +# SiteMaps ensure that your content is more findable in Google, Google Scholar, and other major search engines. +0 0,8,16 * * * $DSPACE/bin/dspace generate-sitemaps > /dev/null + +#---------------- +# DAILY TASKS +# (Recommended to be run once per day. Feel free to tweak the scheduled times below.) +#---------------- + +# Update the OAI-PMH index with the newest content (and re-optimize that index) at midnight every day +# NOTE: ONLY NECESSARY IF YOU ARE RUNNING OAI-PMH +# (This ensures new content is available via OAI-PMH and ensures the OAI-PMH index is optimized for better performance) +#0 0 * * * $DSPACE/bin/dspace oai import -o > /dev/null + +# Clean and Update the Discovery indexes at midnight every day +# (This ensures that any deleted documents are cleaned from the Discovery search/browse index) +0 0 * * * $DSPACE/bin/dspace index-discovery > /dev/null + +# Re-Optimize the Discovery indexes at 12:30 every day +# (This ensures that the Discovery Solr Index is re-optimized for better performance) +30 0 * * * $DSPACE/bin/dspace index-discovery -o > /dev/null + +# Cleanup Web Spiders from DSpace Statistics Solr Index at 01:00 every day +# NOTE: ONLY NECESSARY IF YOU ARE RUNNING SOLR STATISTICS +# (This removes any known web spiders from your usage statistics) +0 1 * * * $DSPACE/bin/dspace stats-util -i + +# Re-Optimize DSpace Statistics Solr Index at 01:30 every day +# NOTE: ONLY NECESSARY IF YOU ARE RUNNING SOLR STATISTICS +# (This ensures that the Statistics Solr Index is re-optimized for better performance) +30 1 * * * $DSPACE/bin/dspace stats-util -o + +# Send out subscription e-mails at 02:00 every day +# (This sends an email to any users who have "subscribed" to a Collection, notifying them of newly added content.) +0 2 * * * $DSPACE/bin/dspace sub-daily + +# Run the media filter at 03:00 every day. +# (This task ensures that thumbnails are generated for newly add images, +# and also ensures full text search is available for newly added PDF/Word/PPT/HTML documents) +0 3 * * * $DSPACE/bin/dspace filter-media + +# Run any Curation Tasks queued from the Admin UI at 04:00 every day +# (Ensures that any curation task that an administrator "queued" from the Admin UI is executed +# asynchronously behind the scenes) +0 4 * * * $DSPACE/bin/dspace curate -q admin_ui + +#---------------- +# WEEKLY TASKS +# (Recommended to be run once per week, but can be run more or less frequently, based on your local needs/policies) +#---------------- +# Run the checksum checker at 04:00 every Sunday +# By default it runs through every file (-l) and also prunes old results (-p) +# (This re-verifies the checksums of all files stored in DSpace. If any files have been changed/corrupted, checksums will differ.) +0 4 * * * $DSPACE/bin/dspace checker -l -p +# NOTE: LARGER SITES MAY WISH TO USE DIFFERENT OPTIONS. The above "-l" option tells DSpace to check *everything*. +# If your site is very large, you may need to only check a portion of your content per week. The below commented-out task +# would instead check all the content it can within *one hour*. The next week it would start again where it left off. +#0 4 * * 0 $DSPACE/bin/dspace checker -d 1h -p + +# Mail the results of the checksum checker (see above) to the configured "mail.admin" at 05:00 every Sunday. +# (This ensures the system administrator is notified whether any checksums were found to be different.) +0 5 * * 0 $DSPACE/bin/dspace checker-emailer + +#---------------- +# MONTHLY TASKS +# (Recommended to be run once per month, but can be run more or less frequently, based on your local needs/policies) +#---------------- +# Permanently delete any bitstreams flagged as "deleted" in DSpace, on the first of every month at 01:00 +# (This ensures that any files which were deleted from DSpace are actually removed from your local filesystem. +# By default they are just marked as deleted, but are not removed from the filesystem.) +0 1 1 * * $DSPACE/bin/dspace cleanup > /dev/null + +#---------------- +# YEARLY TASKS (Recommended to be run once per year) +#---------------- +# At 2:00AM every January 1, "shard" the DSpace Statistics Solr index. +# This ensures each year has its own Solr index, which improves performance. +# NOTE: ONLY NECESSARY IF YOU ARE RUNNING SOLR STATISTICS +# NOTE: This is scheduled here for 2:00AM so that it happens *after* the daily cleaning & re-optimization of this index. +0 2 1 1 * $DSPACE/bin/dspace stats-util -s diff --git a/participatorio-utils/admin_scripts-crontab/root_crontab.txt b/participatorio-utils/admin_scripts-crontab/root_crontab.txt new file mode 100644 index 0000000000000000000000000000000000000000..74fed68f44c820feb48c276d4013b985f77d72b7 --- /dev/null +++ b/participatorio-utils/admin_scripts-crontab/root_crontab.txt @@ -0,0 +1,7 @@ +#-------------------------------------------------------------------------------------------------------------- +# HOW TO USE: +# To add it to crontab, execute "$ crontab e" as root user and add the following content to the end of file +#-------------------------------------------------------------------------------------------------------------- + +#Create and adjust permissions of dspace's logs to avoid permission problems +30 23 * * * /home/dspace/admin-scripts/create-permission_dspace_logs.sh diff --git a/participatorio-utils/iframe_example/ROOT/META-INF/context.xml b/participatorio-utils/iframe_example/ROOT/META-INF/context.xml new file mode 100644 index 0000000000000000000000000000000000000000..5a7783de874eee65103ea05327c7ee753f40e95f --- /dev/null +++ b/participatorio-utils/iframe_example/ROOT/META-INF/context.xml @@ -0,0 +1,2 @@ +<Context path="/" + antiResourceLocking="false" /> diff --git a/participatorio-utils/iframe_example/ROOT/index.html b/participatorio-utils/iframe_example/ROOT/index.html new file mode 100644 index 0000000000000000000000000000000000000000..508fc8e4a8aed4cdafed69ba4fbdfa49a6b856a2 --- /dev/null +++ b/participatorio-utils/iframe_example/ROOT/index.html @@ -0,0 +1,40 @@ +<!DOCTYPE html> + +<html lang="pt-br"> + <head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + + <body> + + <div id='iframeDspace_div' /> + + </body> +</html> + +<script type="text/javascript"> + + window.addEventListener('load', function(){ createDspaceIframe() }, true); + + window.addEventListener('message', function(e){ updateWindowUrl(e) }, true); + + function dspaceBaseUrl(){ return 'http://localhost:8080'; } + + function createDspaceIframe(){ + var iframe = document.createElement('iframe'); + + iframe.id="dspaceIframe"; + iframe.frameBorder=0; + iframe.width="700px"; + iframe.height="700px"; + + iframe.setAttribute("src", dspaceBaseUrl()+'/xmlui/'+document.location.hash); + + document.getElementById('iframeDspace_div').appendChild(iframe); + } + + function updateWindowUrl(dspaceMsg){ + if (dspaceMsg.origin == dspaceBaseUrl()){ + document.location.hash = dspaceMsg.data; + } + } + +</script> diff --git a/participatorio-utils/participatorio_metadata_additions.xml b/participatorio-utils/participatorio_metadata_additions.xml new file mode 100644 index 0000000000000000000000000000000000000000..e05566ad5b71b06ee2067b94d12049c876df52d9 --- /dev/null +++ b/participatorio-utils/participatorio_metadata_additions.xml @@ -0,0 +1,141 @@ +<!-- Metadados DublinCore adicionados ao Dspace Participatorio --> +<!-- ${DSPACEDIR}/bin/dspace dsrun org.dspace.administer.MetadataImporter -f ${THIS_FILE} --> +<dspace-dc-types> + <dc-type> + <schema>dc</schema> + <element>description</element> + <qualifier>affiliation</qualifier> + <scope_note>Affiliation</scope_note> + </dc-type> + <dc-type> + <schema>dc</schema> + <element>description</element> + <qualifier>publicationplace</qualifier> + <scope_note>Place of Publication</scope_note> + </dc-type> + <dc-type> + <schema>dc</schema> + <element>description</element> + <qualifier>edition</qualifier> + <scope_note>Release Edition</scope_note> + </dc-type> + <dc-type> + <schema>dc</schema> + <element>description</element> + <qualifier>numberofpages</qualifier> + <scope_note>Number of Pages</scope_note> + </dc-type> + <dc-type> + <schema>dc</schema> + <element>description</element> + <qualifier>grade</qualifier> + <scope_note>Grade</scope_note> + </dc-type> + <dc-type> + <schema>dc</schema> + <element>description</element> + <qualifier>supervisor</qualifier> + <scope_note>Supervisor</scope_note> + </dc-type> + <dc-type> + <schema>dc</schema> + <element>description</element> + <qualifier>cosupervisor</qualifier> + <scope_note>Co-Supervisor</scope_note> + </dc-type> + <dc-type> + <schema>dc</schema> + <element>description</element> + <qualifier>jurymembers</qualifier> + <scope_note>Members of the jury</scope_note> + </dc-type> + <dc-type> + <schema>dc</schema> + <element>description</element> + <qualifier>defenselocation</qualifier> + <scope_note>Location where the defense took place</scope_note> + </dc-type> + <dc-type> + <schema>dc</schema> + <element>description</element> + <qualifier>defensedate</qualifier> + <scope_note>Date on which the defense occurred</scope_note> + </dc-type> + <dc-type> + <schema>dc</schema> + <element>description</element> + <qualifier>defenceinstitution</qualifier> + <scope_note>Institution where the defense took place</scope_note> + </dc-type> + <dc-type> + <schema>dc</schema> + <element>description</element> + <qualifier>defensedepartment</qualifier> + <scope_note>Department where the defense took place</scope_note> + </dc-type> + <dc-type> + <schema>dc</schema> + <element>description</element> + <qualifier>programme</qualifier> + <scope_note>Programme</scope_note> + </dc-type> + +<!--Feito da maneira que foi pedido: + - Diretor (dc.creator.director); + - Roteirista (dc.creator.screenplay); + - Produção (dc.creator.production); + - Tempo de Duração (dc.coverage.temporal); + - Sistema de Cor (dc.type.color) + - Categoria (dc.xxxx.xxxx); + - Formato da Cópia (dc.xxxx.xxxx); + - Tratamento (dc.format.material); + --> + <dc-type> + <schema>dc</schema> + <element>creator</element> + <qualifier>director</qualifier> + <scope_note>Director</scope_note> + </dc-type> + <dc-type> + <schema>dc</schema> + <element>creator</element> + <qualifier>screenplay</qualifier> + <scope_note>Screenplay</scope_note> + </dc-type> + <dc-type> + <schema>dc</schema> + <element>creator</element> + <qualifier>production</qualifier> + <scope_note>Production</scope_note> + </dc-type> + <dc-type> + <schema>dc</schema> + <element>coverage</element> + <qualifier>temporal</qualifier> + <scope_note>Temporal</scope_note> + </dc-type> + <dc-type> + <schema>dc</schema> + <element>type</element> + <qualifier>color</qualifier> + <scope_note>Color system</scope_note> + </dc-type> + <dc-type> + <schema>dc</schema> + <element>description</element> + <qualifier>category</qualifier> + <scope_note>Category</scope_note> + </dc-type> + <dc-type> + <schema>dc</schema> + <element>description</element> + <qualifier>copyformat</qualifier> + <scope_note>Copy format</scope_note> + </dc-type> + <dc-type> + <schema>dc</schema> + <element>format</element> + <qualifier>material</qualifier> + <scope_note>Material</scope_note> + </dc-type> +</dspace-dc-types> diff --git a/participatorio-utils/pdf_thumbnails_support/install_pdf-thumbnails_support.sh b/participatorio-utils/pdf_thumbnails_support/install_pdf-thumbnails_support.sh new file mode 100644 index 0000000000000000000000000000000000000000..71bec11c9e931f1148d33e90025723caa1da7576 --- /dev/null +++ b/participatorio-utils/pdf_thumbnails_support/install_pdf-thumbnails_support.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +LIB_JAI_IMAGEIO="./participatorio-utils/pdf_thumbnails_support/libs/jai_imageio-1.0_01.jar" +LIB_JAI_CORE="./participatorio-utils/pdf_thumbnails_support/libs/jai_core-1.1.2_01.jar" + +if [[ ! -e ${LIB_JAI_IMAGEIO} || ! -e ${LIB_JAI_CORE} ]]; then + echo "Os arquivos \.jar\" das bibliotecas necessárias não foram encontrados." + echo "Esse script deve ser executado no diretório raiz do código-fonte do sistema (ex.: /home/dspace/src/)." + exit 1 +fi + +mvn install:install-file \ + -Dfile=${LIB_JAI_IMAGEIO} \ + -DgroupId=com.sun.media \ + -DartifactId=jai_imageio \ + -Dversion=1.0_01 \ + -Dpackaging=jar \ + -DgeneratePom=true + +if [[ $? == 1 ]]; then + echo "Aconteceu algum erro durante a instalacao da lib: \"jai_imageio\"." + exit 1 +fi + +mvn install:install-file \ + -Dfile=${LIB_JAI_CORE} \ + -DgroupId=javax.media \ + -DartifactId=jai_core \ + -Dversion=1.1.2_01 \ + -Dpackaging=jar \ + -DgeneratePom=true + +if [[ $? == 1 ]]; then + echo "Aconteceu algum erro durante a instalacao da lib: \"jai_core\"." + exit 1 +fi + +echo "" +echo "####################################################" +echo "" +echo "A instalacao das bibliotecas foi bem sucedida!" +echo "Para finalizar o processo:" +echo "" +echo " * Instale o pacote \"xpdf\":" +echo " $ apt-get install xpdf" +echo "" +echo " * Para gerar os thumbnails, execute:" +echo " $ [DSPACE_INSTALL_DIR]/bin/dspace filter-media" +echo "" +echo "####################################################" +echo "" diff --git a/participatorio-utils/pdf_thumbnails_support/libs/jai_core-1.1.2_01.jar b/participatorio-utils/pdf_thumbnails_support/libs/jai_core-1.1.2_01.jar new file mode 100644 index 0000000000000000000000000000000000000000..1e784a641b0ca613561d8ceebc93f0c3697464ed Binary files /dev/null and b/participatorio-utils/pdf_thumbnails_support/libs/jai_core-1.1.2_01.jar differ diff --git a/participatorio-utils/pdf_thumbnails_support/libs/jai_imageio-1.0_01.jar b/participatorio-utils/pdf_thumbnails_support/libs/jai_imageio-1.0_01.jar new file mode 100644 index 0000000000000000000000000000000000000000..50071ad67fb0d81cc0ba59714f5aee151d3115ed Binary files /dev/null and b/participatorio-utils/pdf_thumbnails_support/libs/jai_imageio-1.0_01.jar differ diff --git a/participatorio-utils/scripts/acompanha_logs.sh b/participatorio-utils/scripts/acompanha_logs.sh new file mode 100755 index 0000000000000000000000000000000000000000..a6d2f4155154d9c494c23ce8c86291e56658ef95 --- /dev/null +++ b/participatorio-utils/scripts/acompanha_logs.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +DSPACE_HOME="/home/dspace/webapp/" +DATE=$(date +%Y-%m-%d) + +tail -f /var/lib/tomcat7/logs/catalina.out \ + /var/lib/tomcat7/logs/*${DATE}.log \ + ${DSPACE_HOME}/log/*${DATE} \ + ${DSPACE_HOME}/handle-server/*.log diff --git a/participatorio-utils/scripts/catalina-java_exports.sh b/participatorio-utils/scripts/catalina-java_exports.sh new file mode 100755 index 0000000000000000000000000000000000000000..e5b8c12e572b9240ebde2fbc55de9b67fe2c09e1 --- /dev/null +++ b/participatorio-utils/scripts/catalina-java_exports.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +export JAVA_OPTS="-Dfile.encoding=UTF-8 -Xms128m -Xmx1024m -XX:PermSize=64m -XX:MaxPermSize=256m" +export CATALINA_OPTS="-Xms512m -Xmx2g" diff --git a/participatorio-utils/scripts/compila_sistema_essencial.sh b/participatorio-utils/scripts/compila_sistema_essencial.sh new file mode 100755 index 0000000000000000000000000000000000000000..2a0a5fdd0053e56332fcb2afd49c44b91b99cad5 --- /dev/null +++ b/participatorio-utils/scripts/compila_sistema_essencial.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +mvn -Pxpdf-mediafilter-support package -P \ + "!dspace-lni, + !dspace-sword, + !dspace-swordv2, + !dspace-rest, + !dspace-jspui" + +if [[ $? == 1 ]]; then + echo "Aconteceu algum erro durante a compilacao!" + exit 1 +fi + +(cd dspace/target/dspace-4.1-build && ant update) + +if [[ $? == 1 ]]; then + echo "Aconteceu algum erro durante a instalacao" + exit 1 +fi + +echo "PRONTO" + +exit 0 diff --git a/participatorio-utils/scripts/compila_somente_jspui.sh b/participatorio-utils/scripts/compila_somente_jspui.sh new file mode 100755 index 0000000000000000000000000000000000000000..b029f4ecf96f83b0041fbca9c52d2061bc2d4310 --- /dev/null +++ b/participatorio-utils/scripts/compila_somente_jspui.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +mvn -Pxpdf-mediafilter-support package -P \ + "!dspace-lni, + !dspace-oai, + !dspace-sword, + !dspace-swordv2, + !dspace-rest, + !dspace-xmlui" + +if [[ $? == 1 ]]; then + echo "Aconteceu algum erro durante a compilacao!" + exit 1 +fi + +(cd dspace/target/dspace-4.1-build && ant update) + +if [[ $? == 1 ]]; then + echo "Aconteceu algum erro durante a instalacao" + exit 1 +fi + +echo "PRONTO" + +exit 0 diff --git a/participatorio-utils/scripts/compila_somente_xmlui.sh b/participatorio-utils/scripts/compila_somente_xmlui.sh new file mode 100755 index 0000000000000000000000000000000000000000..978a426749553dcbf4f70d1394e8e667de6d0d84 --- /dev/null +++ b/participatorio-utils/scripts/compila_somente_xmlui.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +mvn -Pxpdf-mediafilter-support package -P \ + "!dspace-lni, + !dspace-oai, + !dspace-sword, + !dspace-swordv2, + !dspace-rest, + !dspace-jspui" + +if [[ $? == 1 ]]; then + echo "Aconteceu algum erro durante a compilacao!" + exit 1 +fi + +(cd dspace/target/dspace-4.1-build && ant update) + +if [[ $? == 1 ]]; then + echo "Aconteceu algum erro durante a instalacao" + exit 1 +fi + +echo "PRONTO" + +exit 0 diff --git a/participatorio-utils/scripts/copia_messages-properties.sh b/participatorio-utils/scripts/copia_messages-properties.sh new file mode 100755 index 0000000000000000000000000000000000000000..13784650c7a14aedafe959c3c594d818ebbbcafa --- /dev/null +++ b/participatorio-utils/scripts/copia_messages-properties.sh @@ -0,0 +1,13 @@ +while read L; do + TAG=$(echo $L | cut -d "=" -f1 | sed "s#\ ##g") + if [[ $(echo $TAG | grep -c "\.") == 1 ]]; then + PTBR=$(grep "^${TAG}\ " Messages_pt_BR.properties) + if [[ $(echo $PTBR | wc -m) > 1 ]]; then + echo $PTBR + else + echo $L + fi + else + echo $L + fi +done < Messages.properties diff --git a/participatorio-utils/scripts/corrige_permissoes.sh b/participatorio-utils/scripts/corrige_permissoes.sh new file mode 100755 index 0000000000000000000000000000000000000000..2ca3f2d339bf26a9f748aa1dfbb2c3dad135a527 --- /dev/null +++ b/participatorio-utils/scripts/corrige_permissoes.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +chown -R dspace:tomcat7 /home/dspace/webapp/ +chmod -R g+w /home/dspace/webapp/ diff --git a/participatorio-utils/scripts/create_pqsl_db.sh b/participatorio-utils/scripts/create_pqsl_db.sh new file mode 100755 index 0000000000000000000000000000000000000000..7e2f16a7d15b751c660c0269ca6ead9917c01434 --- /dev/null +++ b/participatorio-utils/scripts/create_pqsl_db.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +if [[ $# != 2 ]]; then + echo -e "" + echo -e "Parametros errados! Utilze:" + echo -e "${0} <USERNAME> <DATABASE>" + echo -e "Ex.: ${0} dspace_xyz12 dspace_xyz12" + echo -e "" + exit 1 +fi + +username=${1} +dbname=${2} + +createdb -U ${username} -h localhost -E UNICODE ${dbname} diff --git a/participatorio-utils/scripts/create_pqsl_user.sh b/participatorio-utils/scripts/create_pqsl_user.sh new file mode 100755 index 0000000000000000000000000000000000000000..c9c4eebbf338149c842c689d3ffddc6505855c30 --- /dev/null +++ b/participatorio-utils/scripts/create_pqsl_user.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +if [[ $# != 1 ]]; then + echo -e "" + echo -e "Parametros errados! Utilze:" + echo -e "${0} <USERNAME>" + echo -e "Ex.: ${0} dspace_xyz12" + echo -e "" + exit 1 +fi + +username=${1} + +createuser -h localhost -U postgres -d -A -P ${username} diff --git a/participatorio-utils/scripts/exporta_dados_site.sh b/participatorio-utils/scripts/exporta_dados_site.sh new file mode 100755 index 0000000000000000000000000000000000000000..1e13b4b45868667d4437ee9f64a29ddce1ad1114 --- /dev/null +++ b/participatorio-utils/scripts/exporta_dados_site.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +if [[ $# != 4 ]]; then + echo -e "" + echo -e "Parametros errados! Utilze:" + echo -e "${0} <DSPACE_BIN> <EPERSON> <HANDLE_PREFIX> <EXPORT_DIR>" + echo -e "Ex.: ${0} /home/dspace/webapp/bin/dspace adm@email.com 123456789 /tmp" + echo -e "" + exit 1 +fi + +DSPACE_BIN=${1} +EPERSON=${2} +HANDLE_PREFIX=${3} +EXPORT_DIR=${4} + +EXPORT_NAME="dspace_export_$(date +%d-%m-%Y)" +mkdir -p ${EXPORT_DIR}/${EXPORT_NAME}/ + +${DSPACE_BIN} packager -d -a -t AIP -e ${EPERSON} -i ${HANDLE_PREFIX}/0 ${EXPORT_DIR}/${EXPORT_NAME}/SITE_AIP.zip diff --git a/participatorio-utils/scripts/importa_dados_site.sh b/participatorio-utils/scripts/importa_dados_site.sh new file mode 100755 index 0000000000000000000000000000000000000000..8ac8fcf04b8a313938c661f552c797fe3c1d6580 --- /dev/null +++ b/participatorio-utils/scripts/importa_dados_site.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +if [[ $# != 4 ]]; then + echo -e "" + echo -e "Parametros errados! Utilze:" + echo -e "${0} <DSPACE_BIN> <EPERSON> <HANDLE_PREFIX> <AIP_PACKAGE_ZIPFILE>" + echo -e "Ex.: ${0} /home/dspace/webapp/bin/dspace adm@email.com 123456789 /tmp/dspace_export_04-04-2014/SITE_AIP.zip" + echo -e "" + exit 1 +fi + +DSPACE_BIN=${1} +EPERSON=${2} +HANDLE_PREFIX=${3} +AIP_PACKAGE_ZIPFILE=${4} + +${DSPACE_BIN} packager -r -a -f -t AIP -e ${EPERSON} -i ${HANDLE_PREFIX}/0 ${AIP_PACKAGE_ZIPFILE} diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..6eeba3723af3e2cd115d795a6c5fc1af19796104 --- /dev/null +++ b/pom.xml @@ -0,0 +1,1333 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.dspace</groupId> + <artifactId>dspace-parent</artifactId> + <packaging>pom</packaging> + <version>4.1</version> + <name>DSpace Parent Project</name> + <description> + DSpace open source software is a turnkey institutional repository application. + </description> + <url>https://github.com/dspace/DSpace</url> + + <organization> + <name>DuraSpace</name> + <url>http://www.dspace.org</url> + </organization> + + <!-- brings the sonatype snapshot repository and signing requirement on board --> + <parent> + <groupId>org.sonatype.oss</groupId> + <artifactId>oss-parent</artifactId> + <version>7</version> + <relativePath /> + </parent> + + <!--Force UTF-8 encoding during build on all platforms--> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <java.version>1.6</java.version> <!-- DSpace requires Java 1.6 or higher --> + <lucene.version>4.4.0</lucene.version> + <solr.version>4.4.0</solr.version> + <slf4j.version>1.6.1</slf4j.version> + <!-- 'root.basedir' is the path to the root [dspace-src] dir. It must be redefined by each child POM, + as it is used to reference the LICENSE_HEADER and *.properties file(s) in that directory. --> + <root.basedir>${basedir}</root.basedir> + </properties> + + <build> + <!-- Define Maven Plugin Settings that should be inherited to ALL submodule POMs. + (NOTE: individual POMs can override specific settings). --> + <pluginManagement> + <plugins> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <version>2.3.2</version> + <configuration> + <source>${java.version}</source> + <target>${java.version}</target> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <version>2.3.2</version> + <configuration> + <archive> + <manifest> + <addDefaultImplementationEntries>true</addDefaultImplementationEntries> + <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries> + </manifest> + </archive> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-war-plugin</artifactId> + <!-- We'd rather this be an open-ended range of versions. + But, because of a Maven bug, we must force a specific version: + http://jira.codehaus.org/browse/MNG-2742 + Once the bug is fixed, we should put open-ended range in dspace-pom --> + <version>2.1.1</version> + <configuration> + <failOnMissingWebXml>false</failOnMissingWebXml> + <archive> + <manifest> + <addDefaultImplementationEntries>true</addDefaultImplementationEntries> + <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries> + </manifest> + </archive> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.6</version> + <!-- tests whose name starts by Abstract will be ignored --> + <configuration> + <excludes> + <exclude>**/Abstract*</exclude> + </excludes> + <!-- + Enable to debug Maven Surefire tests in remote proces + <debugForkedProcess>true</debugForkedProcess> + --> + <!-- required when running JMockit under Java 1.5 --> + <argLine>-javaagent:"${settings.localRepository}"/org/dspace/dependencies/jmockit/dspace-jmockit/0.999.4/dspace-jmockit-0.999.4.jar</argLine> + </configuration> + </plugin> + <plugin> + <artifactId>maven-assembly-plugin</artifactId> + <version>2.2.1</version> + </plugin> + <plugin> + <groupId>com.mycila.maven-license-plugin</groupId> + <artifactId>maven-license-plugin</artifactId> + <version>1.9.0</version> + </plugin> + </plugins> + </pluginManagement> + + <!-- These plugin settings only apply to this single POM and are not inherited + to any submodules. --> + <plugins> + <!-- Ensure that any *.properties files have UTF-8 chars encoded (e.g. "\u00e9") *before* using them to filter dspace.cfg and other configs --> + <plugin> + <artifactId>maven-antrun-plugin</artifactId> + <version>1.7</version> + <executions> + <execution> + <id>native2ascii-utf8</id> + <phase>generate-resources</phase> + <configuration> + <target name="Encode any UTF-8 chars in [src]/*.properties"> + <!-- Run 'native2ascii' to encode UTF-8 characters in properties files. Place the resulting file(s) in /target --> + <native2ascii encoding="UTF8" src="${root.basedir}" dest="${root.basedir}/target" includes="*.properties" /> + </target> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + </executions> + <!-- Required dependencies for native2ascii to function --> + <dependencies> + <dependency> + <groupId>com.sun</groupId> + <artifactId>tools</artifactId> + <version>${java.version}</version> + <scope>system</scope> + <!-- Path to tools.jar (containing native2ascii tool) is determined by a profile (see below) --> + <systemPath>${toolsjar}</systemPath> + </dependency> + </dependencies> + </plugin> + + <plugin> + <artifactId>maven-release-plugin</artifactId> + <version>2.3.2</version> + <configuration> + <!-- During release:perform, enable the "release" profile (see below) --> + <releaseProfiles>release</releaseProfiles> + <goals>deploy</goals> + <!-- Suggest tagging the release in SCM as "dspace-[version]" --> + <tagNameFormat>dspace-@{project.version}</tagNameFormat> + <!-- Auto-Version all modules the same as the parent module --> + <autoVersionSubmodules>true</autoVersionSubmodules> + </configuration> + </plugin> + <plugin> + <groupId>com.mycila.maven-license-plugin</groupId> + <artifactId>maven-license-plugin</artifactId> + <configuration> + <!-- License header file (can be a URL, but that's less stable if external site is down on occasion) --> + <header>${root.basedir}/LICENSE_HEADER</header> + <!--Just check headers of everything in the /src directory --> + <includes> + <include>src/**</include> + </includes> + <!--Use all default exclusions for IDE files & Maven files, see: + http://code.google.com/p/maven-license-plugin/wiki/Configuration#Default_excludes --> + <useDefaultExcludes>true</useDefaultExcludes> + <!-- Add some default DSpace exclusions not covered by <useDefaultExcludes> + Individual Maven projects may choose to override these defaults. --> + <excludes> + <exclude>**/src/test/resources/**</exclude> + <exclude>**/src/test/data/**</exclude> + <exclude>**/testEnvironment.properties</exclude> + <exclude>**/META-INF/**</exclude> + <exclude>**/robots.txt</exclude> + <exclude>**/*.LICENSE</exclude> + <exclude>**/LICENSE*</exclude> + <exclude>**/README*</exclude> + <exclude>**/readme*</exclude> + <exclude>**/.gitignore</exclude> + <exclude>**/build.properties*</exclude> + </excludes> + <mapping> + <!-- Custom DSpace file extensions which are not recognized by maven-release-plugin: + *.xmap, *.xslt, *.wsdd, *.wsdl, *.LICENSE --> + <xmap>XML_STYLE</xmap> + <xslt>XML_STYLE</xslt> + <wsdd>XML_STYLE</wsdd> + <wsdl>XML_STYLE</wsdl> + <LICENSE>TEXT</LICENSE> + </mapping> + <encoding>UTF-8</encoding> + <!-- maven-license-plugin recommends a strict check (e.g. check spaces/tabs too) --> + <strictCheck>true</strictCheck> + </configuration> + <executions> + <execution> + <id>check-headers</id> + <phase>verify</phase> + <goals> + <goal>check</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <profiles> + + <!-- By default the main dspace.cfg file will be filtered during the build + using the "build.properties" file. This profile takes effect, unless + "-Denv" is passed in (see 'environment' profile below for more info). --> + <profile> + <id>default</id> + <activation> + <property> + <name>!env</name> + </property> + </activation> + <properties> + <!-- 'root.basedir' is the relative path to the [dspace-src] root folder --> + <!-- NOTE that we are using the copy in the target dir, which has any Unicode characters encoded (see native2ascii above) --> + <filters.file>${root.basedir}/target/build.properties</filters.file> + </properties> + </profile> + + <!-- Users can pass in an environment flag "-Denv" to tell DSpace to use + a different properties file during its build process. + For example: "mvn package -Denv=test" would build DSpace using the + settings in "test.properties" instead of those in "build.properties" --> + <profile> + <id>environment</id> + <activation> + <property> + <name>env</name> + </property> + </activation> + <properties> + <!-- 'root.basedir' is the relative path to the [dspace-src] root folder --> + <!-- NOTE that we are using the copy in the target dir, which has any Unicode characters encoded (see native2ascii above) --> + <filters.file>${root.basedir}/target/${env}.properties</filters.file> + </properties> + </profile> + + + <!-- This profile ensures that we ONLY generate the Unit Test Environment + if the testEnvironment.xml file is found. That way the Test Environment + is NOT built when running a 'mvn package' on a "binary" release. --> + <profile> + <id>generate-test-env</id> + <activation> + <file> + <exists>src/main/assembly/testEnvironment.xml</exists> + </file> + </activation> + <build> + <plugins> + <!-- This plugin builds the testEnvironment.zip package + based on the specifications in testEnvironment.xml --> + <plugin> + <artifactId>maven-assembly-plugin</artifactId> + <executions> + <execution> + <phase>generate-test-resources</phase> + <goals> + <goal>single</goal> + </goals> + <configuration> + <descriptors> + <descriptor>src/main/assembly/testEnvironment.xml</descriptor> + </descriptors> + <filters> + <filter>src/main/filters/testEnvironment.properties</filter> + </filters> + </configuration> + </execution> + </executions> + <inherited>false</inherited> + </plugin> + </plugins> + </build> + </profile> + + <!-- Determine path to Java Tools JAR. This JAR contains the 'native2ascii' tool (required above by maven-antrun-plugin)--> + <!-- In most platforms Unix/Windows it's named tools.jar. But, on Mac it's classes.jar (see next profile) --> + <profile> + <id>default-java-tools</id> + <activation> + <activeByDefault>true</activeByDefault> + <file> + <exists>${java.home}/../lib/tools.jar</exists> + </file> + </activation> + <properties> + <toolsjar>${java.home}/../lib/tools.jar</toolsjar> + </properties> + </profile> + <profile> + <id>mac-java-tools</id> + <activation> + <activeByDefault>false</activeByDefault> + <file> + <exists>${java.home}/../Classes/classes.jar</exists> + </file> + </activation> + <properties> + <toolsjar>${java.home}/../Classes/classes.jar</toolsjar> + </properties> + </profile> + + + <!-- + These profiles activate the inclusion of various modules into + the DSpace Build process. They activate automatically if the + source module is in the local file system, correctly located + relative to this file. + --> + + <!-- + Builds DSpace "Assembly & Configuration" project + --> + <profile> + <id>dspace</id> + <activation> + <file> + <exists>dspace/pom.xml</exists> + </file> + </activation> + <modules> + <module>dspace</module> + </modules> + </profile> + + <!-- + Builds central API for DSpace + --> + <profile> + <id>dspace-api</id> + <activation> + <file> + <exists>dspace-api/pom.xml</exists> + </file> + </activation> + <modules> + <module>dspace-api</module> + </modules> + </profile> + + <!-- + Builds Services for DSpace + --> + <profile> + <id>dspace-services</id> + <activation> + <file> + <exists>dspace-services/pom.xml</exists> + </file> + </activation> + <modules> + <module>dspace-services</module> + </modules> + </profile> + + <!-- + Builds XOAI Gateway WAR for DSpace + --> + <profile> + <id>dspace-oai</id> + <activation> + <file> + <exists>dspace-oai/pom.xml</exists> + </file> + </activation> + <modules> + <module>dspace-oai</module> + </modules> + </profile> + + <!-- + Builds JSPUI WAR for DSpace + --> + <profile> + <id>dspace-jspui</id> + <activation> + <file> + <exists>dspace-jspui/pom.xml</exists> + </file> + </activation> + <modules> + <module>dspace-jspui</module> + </modules> + </profile> + + <!-- REST Jersey --> + <profile> + <id>dspace-rest</id> + <activation> + <file> + <exists>dspace-rest/pom.xml</exists> + </file> + </activation> + <modules> + <module>dspace-rest</module> + </modules> + </profile> + + + <!-- + Builds SWORD WAR for DSpace + --> + <profile> + <id>dspace-sword</id> + <activation> + <file> + <exists>dspace-sword/pom.xml</exists> + </file> + </activation> + <modules> + <module>dspace-sword</module> + </modules> + </profile> + + + <!-- + Builds SOLR WAR for DSpace + --> + <profile> + <id>dspace-solr</id> + <activation> + <file> + <exists>dspace-solr/pom.xml</exists> + </file> + </activation> + <modules> + <module>dspace-solr</module> + </modules> + </profile> + + <!-- + Builds SWORDv2 WAR for DSpace + --> + <profile> + <id>dspace-swordv2</id> + <activation> + <file> + <exists>dspace-swordv2/pom.xml</exists> + </file> + </activation> + <modules> + <module>dspace-swordv2</module> + </modules> + </profile> + + <!-- + Builds XMLUI WAR for DSpace + --> + <profile> + <id>dspace-xmlui</id> + <activation> + <file> + <exists>dspace-xmlui/pom.xml</exists> + </file> + </activation> + <modules> + <module>dspace-xmlui</module> + </modules> + </profile> + + <!-- + Builds LNI WAR & Client for DSpace + --> + <profile> + <id>dspace-lni</id> + <activation> + <file> + <exists>dspace-lni/pom.xml</exists> + </file> + </activation> + <modules> + <module>dspace-lni</module> + <module>dspace-lni/dspace-lni-client</module> + </modules> + </profile> + + + <!-- + The 'release' profile is used by the 'maven-release-plugin' (see above) + to actually perform a DSpace software release to Maven central. + --> + <profile> + <id>release</id> + <activation> + <activeByDefault>false</activeByDefault> + </activation> + <!-- Activate all modules *except* for the 'dspace' module, + as it does not include any Java source code to release. --> + <modules> + <module>dspace-api</module> + <module>dspace-jspui</module> + <module>dspace-xmlui</module> + <module>dspace-lni</module> + <module>dspace-oai</module> + <module>dspace-rest</module> + <module>dspace-sword</module> + <module>dspace-swordv2</module> + </modules> + </profile> + + <!-- Skip Unit Tests by default, but allow override on command line + by setting property "-Dmaven.test.skip=false" --> + <profile> + <id>skiptests</id> + <activation> + <!-- This profile should be active at all times, unless the user + specifies a different value for "maven.test.skip" --> + <property> + <name>!maven.test.skip</name> + </property> + </activation> + <properties> + <maven.test.skip>true</maven.test.skip> + </properties> + </profile> + + </profiles> + + <!-- + Dependency management provides a means to control which + versions of dependency jars are used for compilation + and packaging into the distribution. Rather than placing + a version in your dependencies, look here first to see if + its already strongly defined in dspace-parent and dspace-api. + --> + <dependencyManagement> + <dependencies> + <!-- DSpace core and endorsed Addons --> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>dspace-api</artifactId> + <version>4.1</version> + </dependency> + <dependency> + <groupId>org.dspace.modules</groupId> + <artifactId>additions</artifactId> + <version>4.1</version> + </dependency> + + <dependency> + <groupId>org.dspace</groupId> + <artifactId>dspace-sword</artifactId> + <version>4.1</version> + <type>jar</type> + <classifier>classes</classifier> + </dependency> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>dspace-sword</artifactId> + <version>4.1</version> + <type>war</type> + </dependency> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>dspace-swordv2</artifactId> + <version>4.1</version> + <type>jar</type> + <classifier>classes</classifier> + </dependency> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>dspace-swordv2</artifactId> + <version>4.1</version> + <type>war</type> + </dependency> + + <dependency> + <groupId>org.dspace</groupId> + <artifactId>dspace-jspui</artifactId> + <version>4.1</version> + <type>jar</type> + <classifier>classes</classifier> + </dependency> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>dspace-jspui</artifactId> + <version>4.1</version> + <type>war</type> + </dependency> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>dspace-oai</artifactId> + <version>4.1</version> + <type>jar</type> + <classifier>classes</classifier> + </dependency> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>dspace-oai</artifactId> + <version>4.1</version> + <type>war</type> + </dependency> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>dspace-lni</artifactId> + <version>4.1</version> + <type>jar</type> + <classifier>classes</classifier> + </dependency> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>dspace-lni-client</artifactId> + <version>4.1</version> + </dependency> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>dspace-lni</artifactId> + <version>4.1</version> + <type>war</type> + </dependency> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>dspace-xmlui</artifactId> + <version>4.1</version> + <type>jar</type> + <classifier>classes</classifier> + </dependency> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>dspace-xmlui</artifactId> + <version>4.1</version> + <type>war</type> + </dependency> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>dspace-services</artifactId> + <version>4.1</version> + </dependency> + <!-- DSpace Localization Packages --> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>dspace-api-lang</artifactId> + <version>[4.0.0,5.0.0)</version> + </dependency> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>dspace-xmlui-lang</artifactId> + <version>[4.0.0,5.0.0)</version> + <type>war</type> + </dependency> + <!-- DSpace third Party Dependencies --> + + <dependency> + <groupId>org.swordapp</groupId> + <artifactId>sword-common</artifactId> + <version>1.1</version> + </dependency> + <!-- Explicitly Specify Latest Version of Spring --> + <dependency> + <artifactId>spring-core</artifactId> + <groupId>org.springframework</groupId> + <version>3.1.1.RELEASE</version> + </dependency> + + <dependency> + <artifactId>spring-beans</artifactId> + <groupId>org.springframework</groupId> + <version>3.1.1.RELEASE</version> + </dependency> + + <dependency> + <artifactId>spring-aop</artifactId> + <groupId>org.springframework</groupId> + <version>3.1.1.RELEASE</version> + </dependency> + + <dependency> + <artifactId>spring-context</artifactId> + <groupId>org.springframework</groupId> + <version>3.1.1.RELEASE</version> + </dependency> + + <dependency> + <artifactId>spring-tx</artifactId> + <groupId>org.springframework</groupId> + <version>3.1.1.RELEASE</version> + </dependency> + + <dependency> + <artifactId>spring-jdbc</artifactId> + <groupId>org.springframework</groupId> + <version>3.1.1.RELEASE</version> + </dependency> + + <dependency> + <artifactId>spring-web</artifactId> + <groupId>org.springframework</groupId> + <version>3.1.1.RELEASE</version> + </dependency> + + <dependency> + <artifactId>spring-webmvc</artifactId> + <groupId>org.springframework</groupId> + <version>3.1.1.RELEASE</version> + </dependency> + + <dependency> + <groupId>org.apache.ant</groupId> + <artifactId>ant</artifactId> + <version>1.7.0</version> + </dependency> + <dependency> + <groupId>org.apache.lucene</groupId> + <artifactId>lucene-core</artifactId> + <version>${lucene.version}</version> + </dependency> + <dependency> + <groupId>org.apache.lucene</groupId> + <artifactId>lucene-analyzers-common</artifactId> + <version>${lucene.version}</version> + </dependency> + <dependency> + <groupId>org.apache.lucene</groupId> + <artifactId>lucene-queryparser</artifactId> + <version>${lucene.version}</version> + </dependency> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>handle</artifactId> + <version>6.2</version> + </dependency> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>jargon</artifactId> + <version>1.4.25</version> + </dependency> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>mets</artifactId> + <version>1.5.2</version> + </dependency> + <dependency> + <groupId>org.dspace.dependencies</groupId> + <artifactId>dspace-tm-extractors</artifactId> + <version>1.0.1</version> + </dependency> + <dependency> + <groupId>commons-cli</groupId> + <artifactId>commons-cli</artifactId> + <version>1.2</version> + </dependency> + <dependency> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + <version>1.3</version> + </dependency> + <dependency> + <groupId>commons-collections</groupId> + <artifactId>commons-collections</artifactId> + <version>3.2</version> + <!-- <version>3.1</version> xmlui - wing --> + </dependency> + <dependency> + <groupId>commons-dbcp</groupId> + <artifactId>commons-dbcp</artifactId> + <version>1.4</version> + </dependency> + <dependency> + <groupId>commons-discovery</groupId> + <artifactId>commons-discovery</artifactId> + <version>0.2</version> + </dependency> + <dependency> + <groupId>commons-fileupload</groupId> + <artifactId>commons-fileupload</artifactId> + <version>1.2.1</version> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.3</version> + </dependency> + <dependency> + <groupId>commons-lang</groupId> + <artifactId>commons-lang</artifactId> + <version>2.6</version> + <!-- <version>2.1</version> in xmlui - wing --> + </dependency> + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + <version>1.1.1</version> + </dependency> + <dependency> + <groupId>commons-pool</groupId> + <artifactId>commons-pool</artifactId> + <version>1.4</version> + </dependency> + <dependency> + <groupId>commons-validator</groupId> + <artifactId>commons-validator</artifactId> + <version>1.4.0</version> + </dependency> + <dependency> + <groupId>javax.mail</groupId> + <artifactId>mail</artifactId> + <version>1.4</version> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + <version>2.5</version> + </dependency> + + <dependency> + <groupId>jaxen</groupId> + <artifactId>jaxen</artifactId> + <version>1.1</version> + <exclusions> + <exclusion> + <artifactId>xom</artifactId> + <groupId>xom</groupId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>jdom</groupId> + <artifactId>jdom</artifactId> + <version>1.0</version> + </dependency> + <dependency> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + <version>1.2.17</version> + </dependency> + <dependency> + <groupId>oro</groupId> + <artifactId>oro</artifactId> + <version>2.0.8</version> + </dependency> + <dependency> + <groupId>org.apache.pdfbox</groupId> + <artifactId>pdfbox</artifactId> + <version>1.6.0</version> + </dependency> + <dependency> + <groupId>org.apache.pdfbox</groupId> + <artifactId>fontbox</artifactId> + <version>1.6.0</version> + </dependency> + <dependency> + <groupId>org.apache.pdfbox</groupId> + <artifactId>jempbox</artifactId> + <version>1.6.0</version> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcprov-jdk15</artifactId> + <version>1.44</version> + </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcmail-jdk15</artifactId> + <version>1.44</version> + </dependency> + <dependency> + <groupId>org.apache.poi</groupId> + <artifactId>poi</artifactId> + <version>3.6</version> + </dependency> + <dependency> + <groupId>org.apache.poi</groupId> + <artifactId>poi-scratchpad</artifactId> + <version>3.6</version> + </dependency> + <dependency> + <groupId>org.apache.poi</groupId> + <artifactId>poi-ooxml</artifactId> + <version>3.6</version> + </dependency> + <dependency> + <groupId>net.java.dev.rome</groupId> + <artifactId>rome</artifactId> + <version>1.0.0</version> + </dependency> + <dependency> + <groupId>rome</groupId> + <artifactId>opensearch</artifactId> + <version>0.1</version> + </dependency> + <dependency> + <groupId>xalan</groupId> + <artifactId>xalan</artifactId> + <version>2.7.0</version> + </dependency> + <dependency> + <groupId>xerces</groupId> + <artifactId>xercesImpl</artifactId> + <version>2.8.1</version> + <!-- <version>2.8.0</version> in xmlui --> + </dependency> + <dependency> + <groupId>xml-apis</groupId> + <artifactId>xmlParserAPIs</artifactId> + <version>2.0.2</version> + </dependency> + <dependency> + <groupId>javax.activation</groupId> + <artifactId>activation</artifactId> + <version>1.1</version> + </dependency> + + <dependency> + <groupId>wsdl4j</groupId> + <artifactId>wsdl4j</artifactId> + <version>1.5.1</version> + </dependency> + <dependency> + <groupId>javax.xml</groupId> + <artifactId>jaxrpc-api</artifactId> + <version>1.1</version> + </dependency> + <dependency> + <groupId>axis</groupId> + <artifactId>axis</artifactId> + <version>1.3</version> + </dependency> + <dependency> + <groupId>axis</groupId> + <artifactId>axis-ant</artifactId> + <version>1.3</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>axis</groupId> + <artifactId>axis-saaj</artifactId> + <version>1.2</version> + </dependency> + <dependency> + <groupId>com.ibm.icu</groupId> + <artifactId>icu4j</artifactId> + <version>51.1</version> + </dependency> + <dependency> + <groupId>postgresql</groupId> + <artifactId>postgresql</artifactId> + <version>9.1-901-1.jdbc4</version> + </dependency> + <dependency> + <groupId>com.oracle</groupId> + <artifactId>ojdbc6</artifactId> + <version>11.2.0.2.0</version> + </dependency> + <dependency> + <groupId>com.sun.media</groupId> + <artifactId>jai_imageio</artifactId> + <version>1.0_01</version> + </dependency> + <dependency> + <groupId>javax.media</groupId> + <artifactId>jai_core</artifactId> + <version>1.1.2_01</version> + </dependency> + <dependency> + <groupId>org.dspace</groupId> + <artifactId>oclc-harvester2</artifactId> + <version>0.1.12</version> + </dependency> + <dependency> + <groupId>commons-httpclient</groupId> + <artifactId>commons-httpclient</artifactId> + <version>3.1</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jcl-over-slf4j</artifactId> + <version>${slf4j.version}</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>${slf4j.version}</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-jdk14</artifactId> + <version>${slf4j.version}</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + <version>${slf4j.version}</version> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.8.1</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.dspace.dependencies.jmockit</groupId> + <artifactId>dspace-jmockit</artifactId> + <version>0.999.4</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + <version>1.2.137</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.databene</groupId> + <artifactId>contiperf</artifactId> + <version>1.06</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.2.1</version> + <scope>compile</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <licenses> + <license> + <name>DuraSpace BSD License</name> + <url>https://raw.github.com/DSpace/DSpace/master/LICENSE</url> + <distribution>repo</distribution> + <comments> + A BSD 3-Clause license for the DSpace codebase. + </comments> + </license> + </licenses> + + <issueManagement> + <system>JIRA</system> + <url>https://jira.duraspace.org/browse/DS</url> + </issueManagement> + + <mailingLists> + <mailingList> + <name>DSpace Technical Users List</name> + <subscribe> + http://lists.sourceforge.net/mailman/listinfo/dspace-tech + </subscribe> + <unsubscribe> + http://lists.sourceforge.net/mailman/listinfo/dspace-tech + </unsubscribe> + <post>dspace-tech AT lists.sourceforge.net</post> + <archive> + http://sourceforge.net/mailarchive/forum.php?forum_name=dspace-tech + </archive> + </mailingList> + <mailingList> + <name>DSpace Developers List</name> + <subscribe> + http://lists.sourceforge.net/mailman/listinfo/dspace-devel + </subscribe> + <unsubscribe> + http://lists.sourceforge.net/mailman/listinfo/dspace-devel + </unsubscribe> + <post>dspace-devel AT lists.sourceforge.net</post> + <archive> + http://sourceforge.net/mailarchive/forum.php?forum_name=dspace-devel + </archive> + </mailingList> + <mailingList> + <name>DSpace General Issues List</name> + <subscribe> + http://lists.sourceforge.net/mailman/listinfo/dspace-general + </subscribe> + <unsubscribe> + http://lists.sourceforge.net/mailman/listinfo/dspace-general + </unsubscribe> + <post>dspace-general AT lists.sourceforge.net</post> + <archive> + http://sourceforge.net/mailarchive/forum.php?forum_name=dspace-general + </archive> + </mailingList> + <mailingList> + <name>DSpace SCM Commit Change-Log</name> + <subscribe> + http://lists.sourceforge.net/mailman/listinfo/dspace-changelog + </subscribe> + <unsubscribe> + http://lists.sourceforge.net/mailman/listinfo/dspace-changelog + </unsubscribe> + <post>noreply AT lists.sourceforge.net</post> + <archive> + http://sourceforge.net/mailarchive/forum.php?forum_name=dspace-changelog + </archive> + </mailingList> + </mailingLists> + + <developers> + <developer> + <name>Andrea Bollini</name> + <email>bollini at users.sourceforge.net</email> + <url>http://www.linkedin.com/in/andreabollini</url> + <organization>CILEA</organization> + <organizationUrl>http://www.cilea.it</organizationUrl> + <roles> + <role>commiter</role> + </roles> + <timezone>+1</timezone> + </developer> + <developer> + <name>Ben Bosman</name> + <email>benbosman at atmire.com</email> + <organization>@mire NV</organization> + <organizationUrl>http://www.atmire.com</organizationUrl> + <roles> + <role>commiter</role> + </roles> + </developer> + <developer> + <name>Mark Diggory</name> + <email>mdiggory at atmire.com</email> + <url>http://purl.org/net/mdiggory/homepage</url> + <organization>@mire NV</organization> + <organizationUrl>http://www.atmire.com</organizationUrl> + <roles> + <role>commiter</role> + </roles> + <timezone>-8</timezone> + </developer> + <developer> + <name>Tim Donohue</name> + <email>tdonohue at users.sourceforge.net</email> + <roles> + <role>commiter</role> + </roles> + </developer> + <developer> + <name>Jim Downing</name> + <email>jimdowning at users.sourceforge.net</email> + <roles> + <role>commiter</role> + </roles> + </developer> + <developer> + <name>Richard Jones</name> + <email>richard-jones at users.sourceforge.net</email> + <roles> + <role>commiter</role> + </roles> + </developer> + <developer> + <name>Claudia Juergen</name> + <email>cjuergen at users.sourceforge.net</email> + <roles> + <role>commiter</role> + </roles> + </developer> + <developer> + <name>Stuart Lewis</name> + <email>stuart at stuartlewis.com</email> + <url>http://stuartlewis.com/</url> + <organization>University of Auckland Library</organization> + <organizationUrl>http://www.library.auckland.ac.nz/</organizationUrl> + <roles> + <role>commiter</role> + </roles> + <timezone>+12</timezone> + </developer> + <developer> + <name>Gabriela Mircea</name> + <email>mirceag at users.sourceforge.net</email> + <roles> + <role>commiter</role> + </roles> + </developer> + <developer> + <name>Scott Phillips</name> + <email>scottphillips at users.sourceforge.net</email> + <roles> + <role>commiter</role> + </roles> + </developer> + <developer> + <name>Richard Rodgers</name> + <email>rrodgers at users.sourceforge.net</email> + <roles> + <role>commiter</role> + </roles> + </developer> + <developer> + <name>James Rutherford</name> + <email>jrutherford at users.sourceforge.net</email> + <roles> + <role>commiter</role> + </roles> + </developer> + <developer> + <name>Kim Shepherd</name> + <email>kims at waikato.ac.nz</email> + <organization>Library Consortium of New Zealand</organization> + <organizationUrl>http://www.lconz.ac.nz/</organizationUrl> + <roles> + <role>commiter</role> + </roles> + <timezone>+12</timezone> + </developer> + <developer> + <name>Larry Stone</name> + <email>lcs at mit.edu</email> + <organization>MIT Libraries</organization> + <organizationUrl>http://libraries.mit.edu</organizationUrl> + <roles> + <role>commiter</role> + </roles> + <timezone>-5</timezone> + </developer> + <developer> + <name>Robert Tansley</name> + <email>rtansley at users.sourceforge.net</email> + <roles> + <role>commiter</role> + </roles> + </developer> + <developer> + <name>Graham Triggs</name> + <email>grahamtriggs at users.sourceforge.net</email> + <roles> + <role>commiter</role> + </roles> + </developer> + <developer> + <name>Jeffrey Trimble</name> + <email /> + <roles> + <role>commiter</role> + </roles> + </developer> + <developer> + <name>Mark H. Wood</name> + <email>mwoodiupui at users.sourceforge.net</email> + <roles> + <role>commiter</role> + </roles> + </developer> + <developer> + <name>Scott Yeadon</name> + <email>syeadon at users.sourceforge.net</email> + <roles> + <role>commiter</role> + </roles> + </developer> + </developers> + + <contributors> + <contributor> + <name>Add Your Name Here and submit a patch!</name> + <email>contributor at myu.edu</email> + <url>http://www.myu.edu/me</url> + <organization>My University</organization> + <organizationUrl>http://www.myu.edu</organizationUrl> + <roles> + <role>developer</role> + </roles> + <timezone>0</timezone> + </contributor> + <contributor> + <name>Pere Villega</name> + <email>pere.villega@gmail.com</email> + <url>http://www.perevillega.com</url> + <organization /> + <organizationUrl /> + <roles> + <role>developer</role> + </roles> + <timezone>0</timezone> + </contributor> + <contributor> + <name>Sands Fish</name> + <email>sands at mit.edu</email> + <organization>MIT Libraries</organization> + <organizationUrl>http://libraries.mit.edu</organizationUrl> + <roles> + <role>developer</role> + </roles> + <timezone>-5</timezone> + </contributor> + <contributor> + <name>Steve Swinsburg</name> + <email>steve.swinsburg@anu.edu.au</email> + <organization>The Australian National University</organization> + <organizationUrl>http://www.anu.edu.au</organizationUrl> + <roles> + <role>developer</role> + </roles> + <timezone>+10</timezone> + </contributor> + </contributors> + + <!-- + The Subversion repository location is used by Continuum to update against + when changes have occurred. This spawns a new build cycle and releases + snapshots into the snapshot repository below. + --> + <scm> + <connection>scm:git:git@github.com:DSpace/DSpace.git</connection> + <developerConnection>scm:git:git@github.com:DSpace/DSpace.git</developerConnection> + <url>git@github.com:DSpace/DSpace.git</url> + <tag>dspace-4.1</tag> + </scm> + + <!-- + Distribution Management is currently used by the Continuum + server to update snapshots it generates. This will also be used + on release to deploy release versions to the repository by the + release manager. + --> + <distributionManagement> + <!-- further distribution management is found upstream in the sonatype parent --> + </distributionManagement> + + <repositories> + <repository> + <id>sonatype-releases</id> + <name>Sonatype Releases Repository</name> + <url>http://oss.sonatype.org/content/repositories/releases/</url> + </repository> + </repositories> + +</project>