Add dspace-rest, using Jersey, light support for Collection / Community

This commit is contained in:
Peter Dietz
2013-09-19 13:35:40 -04:00
parent 84e9f8e718
commit 6ac5842e0a
11 changed files with 544 additions and 0 deletions

5
dspace-rest/LICENSE Normal file
View File

@@ -0,0 +1,5 @@
The contents of this file are subject to the license and copyright
detailed in the LICENSE and NOTICE files at the root of the source
tree and available online at
http://www.dspace.org/license/

16
dspace-rest/README Normal file
View File

@@ -0,0 +1,16 @@
A RESTful web services API for DSpace.
Built on JERSEY
mvn clean package
Deploy /target/rest.war to tomcat.
Endpoints:
- http://localhost:8080/dspace-rest/collections
-- http://localhost:8080/dspace-rest/collections/{collectionID}
-- http://localhost:8080/dspace-rest/collections/{collectionID}?expand=parentCommunityID,parentCommunityIDList,itemIDList
-- http://localhost:8080/dspace-rest/collections/123
- http://localhost:8080/dspace-rest/communities
There is an ?expand= query parameter for expensive operations. You can tack it on the end of /collections endpoints. It is optional, all, some or none.

61
dspace-rest/pom.xml Normal file
View File

@@ -0,0 +1,61 @@
<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.rest</groupId>
<artifactId>dspace-rest</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>DSpace RESTful web services API</name>
<url>http://demo.dspace.org</url>
<dependencies>
<!-- Jersey, for RESTful web services -->
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-servlet</artifactId>
<version>1.17</version>
</dependency>
<!-- JSON serialization, should I use jackson?-->
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.8</version>
</dependency>
<!-- Use DSpace, for now, an older version to minimize spring generated dependency on Discovery -->
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-api</artifactId>
<version>1.8.2</version>
</dependency>
<!-- Connecting to DSpace datasource sets a dependency on Postgres DB-->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.0-801.jdbc3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
<finalName>${artifactId}</finalName>
</build>
</project>

View File

@@ -0,0 +1,77 @@
package org.dspace.rest;
import org.dspace.content.Collection;
import org.dspace.core.Context;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
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 {
final String collectionsPath = "/dspace-rest/collections/";
private static Context context;
/*
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 {
Context context = new Context();
Collection[] collections = Collection.findAll(context);
for(Collection collection : collections) {
everything.append("<li><a href='" + collectionsPath + collection.getID() + "'>" + collection.getID() + " - " + collection.getName() + "</a></li>\n");
}
} catch (SQLException e) {
return "ERROR: " + e.getMessage();
}
return "<html><title>Hello!</title><body>Collections<br/><ul>" + everything.toString() + "</ul>.</body></html> ";
}
@GET
@Path("/")
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public org.dspace.rest.common.Collection[] list(@QueryParam("expand") String expand) {
try {
if(context == null || !context.isValid() ) {
context = new Context();
}
Collection[] collections = Collection.findAll(context);
ArrayList<org.dspace.rest.common.Collection> collectionArrayList = new ArrayList<org.dspace.rest.common.Collection>();
for(Collection collection : collections) {
org.dspace.rest.common.Collection restCollection = new org.dspace.rest.common.Collection(collection, expand);
collectionArrayList.add(restCollection);
}
return collectionArrayList.toArray(new org.dspace.rest.common.Collection[0]);
} catch (SQLException e) {
return null;
}
}
@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) {
return new org.dspace.rest.common.Collection(collection_id, expand);
}
}

View File

@@ -0,0 +1,46 @@
package org.dspace.rest;
import org.dspace.content.Community;
import org.dspace.core.Context;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.sql.SQLException;
/*
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 Context context;
/*
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 Context();
}
Community[] communities = Community.findAllTop(context);
for(Community community : communities) {
everything.append(community.getName() + "<br/>\n");
}
} catch (SQLException e) {
return "ERROR: " + e.getMessage();
}
return "<html><title>Hello!</title><body>Communities:<br/>" + everything.toString() + ".</body></html> ";
}
}

View File

@@ -0,0 +1,27 @@
package org.dspace.rest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
/*
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>/helloworld
*/
@Path("/helloworld")
public class HelloWorld {
/*
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>Hello!</title><body>Hello, world.</body></html> ";
}
}

View File

@@ -0,0 +1,217 @@
package org.dspace.rest.common;
import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.content.ItemIterator;
import org.dspace.core.Context;
import javax.xml.bind.annotation.XmlRootElement;
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
public class Collection {
//Internal value
private Integer collectionID;
//Relationships to other objects
private Integer logoID;
//Exandable relationships
private Integer parentCommunityID;
private List<Integer> parentCommunityIDList = new ArrayList<Integer>();
private List<Integer> itemIDList = new ArrayList<Integer>();
private List<String> expand = new ArrayList<String>();
//Internal metadata
private String name;
private String handle;
private String license;
//Calculated
private Integer numberItems;
private static Context context;
public Collection(){}
public Collection(org.dspace.content.Collection collection, String expand) {
setup(collection, expand);
}
public Collection(Integer collectionID, String expand) {
try {
if(context == null || !context.isValid() ) {
context = new Context();
}
org.dspace.content.Collection collection = org.dspace.content.Collection.find(context, collectionID);
setup(collection, expand);
} catch (Exception e) {
this.setName(e.getMessage());
}
}
private void setup(org.dspace.content.Collection collection, String expand) {
List<String> expandFields = new ArrayList<String>();
if(expand != null) {
expandFields = Arrays.asList(expand.split(","));
}
try {
this.setCollectionID(collection.getID());
this.setName(collection.getName());
this.setHandle(collection.getHandle());
if(expandFields.contains("parentCommunityIDList")) {
Community[] parentCommunities = collection.getCommunities();
for(Community parentCommunity : parentCommunities) {
this.addParentCommunityIDList(parentCommunity.getID());
}
} else {
this.addExpand("parentCommunityIDList");
}
if(expandFields.contains("parentCommunityID")) {
Community parentCommunity = (Community) collection.getParentObject();
this.setParentCommunityID(parentCommunity.getID());
} else {
this.addExpand("parentCommunityID");
}
if(expandFields.contains("itemIDList")) {
ItemIterator childItems = collection.getItems();
while(childItems.hasNext()) {
Item item = childItems.next();
this.addItemIDToList(item.getID());
}
} else {
this.addExpand("itemIDList");
}
if(collection.getLogo() != null) {
this.setLogoID(collection.getLogo().getID());
}
this.setLicense(collection.getLicense());
this.setNumberItems(collection.countItems());
//collection.getMetadata()
} catch (Exception e) {
}
}
//metadata s
//String provenance_description;
//String short_description;
//String introductory_text;
//String copyright_text;
//String side_bar_text;
public Integer getCollectionID() {
return collectionID;
}
public void setCollectionID(Integer id) {
this.collectionID = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getHandle() {
return handle;
}
public void setHandle(String handle) {
this.handle = handle;
}
public Integer getLogoID() {
return logoID;
}
public void setLogoID(Integer logoID) {
this.logoID = logoID;
}
public String getLicense() {
return license;
}
public void setLicense(String license) {
this.license = license;
}
public Integer getNumberItems() {
return numberItems;
}
public void setNumberItems(Integer numberItems) {
this.numberItems = numberItems;
}
public Integer getParentCommunityID() {
return parentCommunityID;
}
public void setParentCommunityID(Integer parentCommunityID) {
this.parentCommunityID = parentCommunityID;
}
public List<Integer> getParentCommunityIDList() {
return parentCommunityIDList;
}
public void setParentCommunityIDList(List<Integer> parentCommunityIDList) {
this.parentCommunityIDList = parentCommunityIDList;
}
public void addParentCommunityIDList(Integer communityParentID) {
this.parentCommunityIDList.add(communityParentID);
}
public List<Integer> getItemIDList() {
return itemIDList;
}
public void setItemIDList(List<Integer> itemIDList) {
this.itemIDList = itemIDList;
}
public void addItemIDToList(Integer itemID) {
this.itemIDList.add(itemID);
}
public List<String> getExpand() {
return expand;
}
public void setExpand(List<String> expand) {
this.expand = expand;
}
public void addExpand(String expandableAttribute) {
this.expand.add(expandableAttribute);
}
}

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<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-2.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd">
<!-- Acquires the DSpace Utility Class with initialized Service Manager -->
<bean id="dspace" class="org.dspace.utils.DSpace"/>
</beans>

View File

@@ -0,0 +1,84 @@
<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.container.servlet.ServletContainer</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>
<context-param>
<param-name>dspace-config</param-name>
<param-value>/dspace/config/dspace.cfg</param-value>
</context-param>
<!-- 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 -->
<param-value>/dspace</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>
</web-app>

View File

View File