diff --git a/dspace-rest/LICENSE b/dspace-rest/LICENSE new file mode 100644 index 000000000000..bc72317dc7e5 --- /dev/null +++ b/dspace-rest/LICENSE @@ -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/ diff --git a/dspace-rest/README b/dspace-rest/README new file mode 100644 index 000000000000..f95acd53ddb1 --- /dev/null +++ b/dspace-rest/README @@ -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. \ No newline at end of file diff --git a/dspace-rest/pom.xml b/dspace-rest/pom.xml new file mode 100644 index 000000000000..e4eada57b7d6 --- /dev/null +++ b/dspace-rest/pom.xml @@ -0,0 +1,61 @@ + + 4.0.0 + org.dspace.rest + dspace-rest + war + 1.0-SNAPSHOT + DSpace RESTful web services API + http://demo.dspace.org + + + + com.sun.jersey + jersey-server + 1.8 + + + com.sun.jersey + jersey-servlet + 1.17 + + + + com.sun.jersey + jersey-json + 1.8 + + + + + org.dspace + dspace-api + 1.8.2 + + + + + commons-dbcp + commons-dbcp + 1.4 + + + postgresql + postgresql + 9.0-801.jdbc3 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.6 + 1.6 + + + + ${artifactId} + + 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 000000000000..bca91e68798b --- /dev/null +++ b/dspace-rest/src/main/java/org/dspace/rest/CollectionsResource.java @@ -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//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("
  • " + collection.getID() + " - " + collection.getName() + "
  • \n"); + } + + } catch (SQLException e) { + return "ERROR: " + e.getMessage(); + } + + return "Hello!Collections
    . "; + } + + @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 collectionArrayList = new ArrayList(); + 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); + } +} 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 000000000000..b0cdc5af6b41 --- /dev/null +++ b/dspace-rest/src/main/java/org/dspace/rest/CommunitiesResource.java @@ -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//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() + "
    \n"); + } + + } catch (SQLException e) { + return "ERROR: " + e.getMessage(); + } + + return "Hello!Communities:
    " + everything.toString() + ". "; + } +} diff --git a/dspace-rest/src/main/java/org/dspace/rest/HelloWorld.java b/dspace-rest/src/main/java/org/dspace/rest/HelloWorld.java new file mode 100644 index 000000000000..401b633d6076 --- /dev/null +++ b/dspace-rest/src/main/java/org/dspace/rest/HelloWorld.java @@ -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//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 "Hello!Hello, world. "; + } +} 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 000000000000..7545e7af6db1 --- /dev/null +++ b/dspace-rest/src/main/java/org/dspace/rest/common/Collection.java @@ -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 parentCommunityIDList = new ArrayList(); + private List itemIDList = new ArrayList(); + + + private List expand = new ArrayList(); + + //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 expandFields = new ArrayList(); + 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 getParentCommunityIDList() { + return parentCommunityIDList; + } + + public void setParentCommunityIDList(List parentCommunityIDList) { + this.parentCommunityIDList = parentCommunityIDList; + } + + public void addParentCommunityIDList(Integer communityParentID) { + this.parentCommunityIDList.add(communityParentID); + } + + + public List getItemIDList() { + return itemIDList; + } + + public void setItemIDList(List itemIDList) { + this.itemIDList = itemIDList; + } + + public void addItemIDToList(Integer itemID) { + this.itemIDList.add(itemID); + } + + public List getExpand() { + return expand; + } + + public void setExpand(List expand) { + this.expand = expand; + } + + public void addExpand(String expandableAttribute) { + this.expand.add(expandableAttribute); + } +} 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 000000000000..ea28e11ce50d --- /dev/null +++ b/dspace-rest/src/main/webapp/WEB-INF/applicationContext.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/dspace-rest/src/main/webapp/WEB-INF/web.xml b/dspace-rest/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 000000000000..0d8be7ae7b5b --- /dev/null +++ b/dspace-rest/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,84 @@ + + + DSpace REST API + com.sun.jersey.spi.container.servlet.ServletContainer + + + com.sun.jersey.config.property.packages + org.dspace.rest + + + com.sun.jersey.api.json.POJOMappingFeature + true + + + 1 + + + DSpace REST API + + /* + + + + dspace-config + /dspace/config/dspace.cfg + + + + + The location of the main DSpace configuration file + dspace.dir + + /dspace + + + + contextConfigLocation + + /WEB-INF/applicationContext.xml + + + + + + org.dspace.app.util.DSpaceContextListener + + + + + org.dspace.servicemanager.servlet.DSpaceKernelServletContextListener + + + + diff --git a/dspace/modules/rest/pom.xml b/dspace/modules/rest/pom.xml new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/dspace/modules/rest/src/main/webapp/.gitignore b/dspace/modules/rest/src/main/webapp/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1