Merge pull request #666 from ctu-developers/master

DS-2168: New REST api with CRUD operations.
This commit is contained in:
Peter Dietz
2014-10-20 12:02:24 -04:00
19 changed files with 4837 additions and 527 deletions

View File

@@ -7,143 +7,849 @@
*/ */
package org.dspace.rest; package org.dspace.rest;
import org.apache.log4j.Logger; import java.io.IOException;
import org.dspace.authorize.AuthorizeException; import java.io.InputStream;
import org.dspace.authorize.AuthorizeManager; import java.net.URLConnection;
import org.dspace.content.DSpaceObject; import java.sql.SQLException;
import org.dspace.core.ConfigurationManager; import java.util.ArrayList;
import org.dspace.core.Constants; import java.util.List;
import org.dspace.rest.common.Bitstream;
import org.dspace.usage.UsageEvent;
import org.dspace.utils.DSpace;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.*; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.io.IOException; import javax.ws.rs.core.Response.Status;
import java.sql.SQLException;
import org.apache.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.content.BitstreamFormat;
import org.dspace.content.Bundle;
import org.dspace.eperson.Group;
import org.dspace.rest.common.Bitstream;
import org.dspace.rest.common.ResourcePolicy;
import org.dspace.rest.exceptions.ContextException;
import org.dspace.storage.bitstore.BitstreamStorageManager;
import org.dspace.storage.rdbms.DatabaseManager;
import org.dspace.storage.rdbms.TableRow;
import org.dspace.usage.UsageEvent;
/** /**
* Created with IntelliJ IDEA. * @author Rostislav Novak (Computing and Information Centre, CTU in Prague)
* User: peterdietz
* Date: 10/2/13
* Time: 5:56 PM
* To change this template use File | Settings | File Templates.
*/ */
// Every DSpace class used without namespace is from package
// org.dspace.rest.common.*. Otherwise namespace is defined.
@Path("/bitstreams") @Path("/bitstreams")
public class BitstreamResource { public class BitstreamResource extends Resource
Logger log = Logger.getLogger(BitstreamResource.class); {
private static final boolean writeStatistics;
static{
writeStatistics=ConfigurationManager.getBooleanProperty("rest","stats",false);
}
//BitstreamList - Not Implemented private static Logger log = Logger.getLogger(BitstreamResource.class);
/**
* Return bitstream properties without file data. It can throws
* WebApplicationException with three response codes. Response code
* NOT_FOUND(404) or UNAUTHORIZED(401) or INTERNAL_SERVER_ERROR(500). Bad
* request is when id of bitstream does not exist. UNAUTHORIZED is if logged
* user into DSpace context have not permission to access bitstream. Server
* error when something went wrong.
*
* @param bitstreamId
* Id of bitstream in DSpace.
* @param expand
* This string defined, which additional options will be added
* into bitstream. Single options are separated by commas without
* space. Options are: "all", "parent".
* @param headers
* If you want to access to item under logged user into context.
* In headers must be set header "rest-dspace-token" with passed
* token from login method.
* @return If user is allowed to read bitstream, it returns instance of
* bitstream. Otherwise, it throws WebApplicationException with
* response code UNAUTHORIZED.
* @throws WebApplicationException
* It can happen on: Bad request, unauthorized, SQL exception
* and context exception(could not create context).
*/
@GET @GET
@Path("/{bitstream_id}") @Path("/{bitstream_id}")
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Bitstream getBitstream(@PathParam("bitstream_id") Integer bitstream_id, @QueryParam("expand") String expand) { public Bitstream getBitstream(@PathParam("bitstream_id") Integer bitstreamId, @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
{
log.info("Reading bitstream(id=" + bitstreamId + ") metadata.");
org.dspace.core.Context context = null; org.dspace.core.Context context = null;
try { Bitstream bitstream = null;
context = new org.dspace.core.Context();
org.dspace.content.Bitstream bitstream = org.dspace.content.Bitstream.find(context, bitstream_id); try
{
context = createContext(getUser(headers));
org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, org.dspace.core.Constants.READ);
writeStats(dspaceBitstream, UsageEvent.Action.VIEW, user_ip, user_agent, xforwarderfor, headers,
request);
bitstream = new Bitstream(dspaceBitstream, expand);
context.complete();
log.trace("Bitsream(id=" + bitstreamId + ") was successfully read.");
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);
} finally {
if(context != null) {
try {
context.complete();
} catch (SQLException e) {
log.error(e.getMessage() + " occurred while trying to close");
}
}
} }
catch (SQLException e)
{
processException("Someting went wrong while reading bitstream(id=" + bitstreamId + ") from database! Message: " + e,
context);
}
catch (ContextException e)
{
processException("Someting went wrong while reading bitstream(id=" + bitstreamId + "), ContextException. Message: "
+ e.getMessage(), context);
}
finally
{
processFinally(context);
}
return bitstream;
} }
/**
* Return all bitstream resource policies from all bundles, in which
* bitstream is.
*
* @param bitstreamId
* Id of bitstream in DSpace.
* @param headers
* If you want to access to item under logged user into context.
* In headers must be set header "rest-dspace-token" with passed
* token from login method.
* @return It returns array of ResourcePolicy.
*/
@GET
@Path("/{bitstream_id}/policy")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public ResourcePolicy[] getBitstreamPolicies(@PathParam("bitstream_id") Integer bitstreamId, @Context HttpHeaders headers)
{
log.info("Reading bitstream(id=" + bitstreamId + ") policies.");
org.dspace.core.Context context = null;
List<ResourcePolicy> policies = new ArrayList<ResourcePolicy>();
try
{
context = createContext(getUser(headers));
org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, org.dspace.core.Constants.READ);
Bundle[] bundles = dspaceBitstream.getBundles();
for (Bundle bundle : bundles)
{
List<org.dspace.authorize.ResourcePolicy> bitstreamsPolicies = bundle.getBitstreamPolicies();
for (org.dspace.authorize.ResourcePolicy policy : bitstreamsPolicies)
{
if (policy.getResourceID() == bitstreamId)
{
policies.add(new ResourcePolicy(policy));
}
}
}
context.complete();
log.trace("Policies for bitsream(id=" + bitstreamId + ") was successfully read.");
}
catch (SQLException e)
{
processException("Someting went wrong while reading policies of bitstream(id=" + bitstreamId
+ "), SQLException! Message: " + e, context);
}
catch (ContextException e)
{
processException("Someting went wrong while reading policies of bitstream(id=" + bitstreamId
+ "), ContextException. Message: " + e.getMessage(), context);
}
finally
{
processFinally(context);
}
return policies.toArray(new ResourcePolicy[0]);
}
/**
* Read list of bitstreams. It throws WebApplicationException with response
* code INTERNAL_SERVER_ERROR(500), if there was problem while reading
* bitstreams from database.
*
* @param limit
* How much bitstreams in list will be. Default value is 100.
* @param offset
* On which index will list starts. Default values is 0.
* @param headers
* If you want to access to item under logged user into context.
* In headers must be set header "rest-dspace-token" with passed
* token from login method.
* @return It returns array of bistreams. In array are not bitstreams on
* which user has not permission to read.
* @throws WebApplicationException
* It is thrown when was problem with database reading or with
* creating context.
*/
@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Bitstream[] getBitstreams(@QueryParam("expand") String expand,
@QueryParam("limit") @DefaultValue("100") Integer limit, @QueryParam("offset") @DefaultValue("0") Integer offset,
@QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
@QueryParam("xforwarderfor") String xforwarderfor, @Context HttpHeaders headers, @Context HttpServletRequest request)
throws WebApplicationException
{
log.info("Reading bitstreams.(offset=" + offset + ",limit=" + limit + ")");
org.dspace.core.Context context = null;
List<Bitstream> bitstreams = new ArrayList<Bitstream>();
try
{
context = createContext(getUser(headers));
org.dspace.content.Bitstream[] dspaceBitstreams = org.dspace.content.Bitstream.findAll(context);
if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0)))
{
log.warn("Pagging was badly set.");
limit = 100;
offset = 0;
}
// TODO If bitsream doesnt not exist it throw exception.
for (int i = offset; (i < (offset + limit)) && (i < dspaceBitstreams.length); i++)
{
if (AuthorizeManager.authorizeActionBoolean(context, dspaceBitstreams[i], org.dspace.core.Constants.READ))
{
if (dspaceBitstreams[i].getParentObject() != null)
{ // To eliminate bitstreams which cause exception, because of
// reading under administrator permissions
bitstreams.add(new Bitstream(dspaceBitstreams[i], expand));
writeStats(dspaceBitstreams[i], UsageEvent.Action.VIEW, user_ip, user_agent,
xforwarderfor, headers, request);
}
}
}
context.complete();
log.trace("Bitstreams were successfully read.");
}
catch (SQLException e)
{
processException("Something get wrong while reading bitstreams from database!. Message: " + e, context);
}
catch (ContextException e)
{
processException("Something get wrong while reading bitstreams, ContextException. Message: " + e.getMessage(),
context);
}
finally
{
processFinally(context);
}
return bitstreams.toArray(new Bitstream[0]);
}
/**
* Read bitstream data. It can throw WebApplicationException with code
* INTERNAL_SERVER_ERROR(500). Caused by three exceptions: IOException if
* there was problem with reading bitstream file. SQLException if there was
* problem while reading from database. And AuthorizeException if there was
* problem with authorization of user logged to DSpace context.
*
* @param bitstreamId
* Id of bitstream, of which will be read data.
* @param headers
* If you want to access to item under logged user into context.
* In headers must be set header "rest-dspace-token" with passed
* token from login method.
* @return Returns response with data with content type of file. It can
* return response code NOT_FOUND(404) if there was bad id of
* bitstream. Or response code UNAUTHORIZED(401) if user is not
* allowed to read bitstream.
* @throws WebApplicationException
* It is throw in this cases: When was problem with reading file
* data. Or was problem with database reading. Or was problem
* with creating context. Or problem with authorization.
*/
@GET @GET
@Path("/{bitstream_id}/retrieve") @Path("/{bitstream_id}/retrieve")
public javax.ws.rs.core.Response getFile(@PathParam("bitstream_id") final Integer bitstream_id, public javax.ws.rs.core.Response getBitstreamData(@PathParam("bitstream_id") Integer bitstreamId,
@QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, @QueryParam("xforwarderfor") String xforwarderfor, @QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
@Context HttpHeaders headers, @Context HttpServletRequest request) { @QueryParam("xforwarderfor") String xforwarderfor, @Context HttpHeaders headers, @Context HttpServletRequest request)
org.dspace.core.Context context = null; throws WebApplicationException
try { {
context = new org.dspace.core.Context();
org.dspace.content.Bitstream bitstream = org.dspace.content.Bitstream.find(context, bitstream_id); log.info("Reading data of bitstream(id=" + bitstreamId + ").");
if(AuthorizeManager.authorizeActionBoolean(context, bitstream, org.dspace.core.Constants.READ)) { org.dspace.core.Context context = null;
if(writeStatistics){ InputStream inputStream = null;
writeStats(context, bitstream_id, user_ip, user_agent, xforwarderfor, headers, request); String type = null;
}
try
return Response.ok(bitstream.retrieve()).type(bitstream.getFormat().getMIMEType()).build(); {
} else { context = createContext(getUser(headers));
org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, org.dspace.core.Constants.READ);
writeStats(dspaceBitstream, UsageEvent.Action.VIEW, user_ip, user_agent, xforwarderfor, headers,
request);
log.trace("Bitsream(id=" + bitstreamId + ") data was successfully read.");
inputStream = dspaceBitstream.retrieve();
type = dspaceBitstream.getFormat().getMIMEType();
context.complete();
}
catch (IOException e)
{
processException("Could not read file of bitstream(id=" + bitstreamId + ")! Message: " + e, context);
}
catch (SQLException e)
{
processException("Something get wrong while reading bitsream(id=" + bitstreamId + ") from database! Message: " + e,
context);
}
catch (AuthorizeException e)
{
processException("Could not retrieve file of bitstream(id=" + bitstreamId + "), AuthorizeException! Message: " + e,
context);
}
catch (ContextException e)
{
processException(
"Could not retrieve file of bitstream(id=" + bitstreamId + "), ContextException! Message: " + e.getMessage(),
context);
}
finally
{
processFinally(context);
}
return Response.ok(inputStream).type(type).build();
}
/**
* Add bitstream policy to all bundles in which bitstream is.
*
* @param bitstreamId
* Id of bitstream in DSpace.
* @param policy
* Policy which will be added. But this atributes does not be
* applied: epersonId,
* @param headers
* If you want to access to item under logged user into context.
* In headers must be set header "rest-dspace-token" with passed
* token from login method.
* @return Returns ok, if was all ok. Otherwise status code 500.
*/
@POST
@Path("/{bitstream_id}/policy")
public javax.ws.rs.core.Response addBitstreamPolicy(@PathParam("bitstream_id") Integer bitstreamId, ResourcePolicy policy,
@Context HttpHeaders headers)
{
log.info("Adding bitstream(id=" + bitstreamId + ") READ policy with permission for group(id=" + policy.getGroupId()
+ ").");
org.dspace.core.Context context = null;
try
{
context = createContext(getUser(headers));
org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, org.dspace.core.Constants.READ);
Bundle[] bundles = dspaceBitstream.getBundles();
for (Bundle bundle : bundles)
{
List<org.dspace.authorize.ResourcePolicy> bitstreamsPolicies = bundle.getBitstreamPolicies();
org.dspace.authorize.ResourcePolicy dspacePolicy = org.dspace.authorize.ResourcePolicy.create(context);
dspacePolicy.setAction(policy.getActionInt());
dspacePolicy.setGroup(Group.find(context, policy.getGroupId()));
dspacePolicy.setResourceID(dspaceBitstream.getID());
dspacePolicy.setResource(dspaceBitstream);
dspacePolicy.setResourceType(org.dspace.core.Constants.BITSTREAM);
dspacePolicy.setStartDate(policy.getStartDate());
dspacePolicy.setEndDate(policy.getEndDate());
dspacePolicy.setRpDescription(policy.getRpDescription());
dspacePolicy.setRpName(policy.getRpName());
dspacePolicy.update();
// dspacePolicy.setRpType(org.dspace.authorize.ResourcePolicy.TYPE_CUSTOM);
bitstreamsPolicies.add(dspacePolicy);
bundle.replaceAllBitstreamPolicies(bitstreamsPolicies);
bundle.update();
}
context.complete();
log.trace("Policy for bitsream(id=" + bitstreamId + ") was successfully added.");
}
catch (SQLException e)
{
processException("Someting went wrong while adding policy to bitstream(id=" + bitstreamId
+ "), SQLException! Message: " + e, context);
}
catch (ContextException e)
{
processException("Someting went wrong while adding policy to bitstream(id=" + bitstreamId
+ "), ContextException. Message: " + e.getMessage(), context);
}
catch (AuthorizeException e)
{
processException("Someting went wrong while adding policy to bitstream(id=" + bitstreamId
+ "), AuthorizeException! Message: " + e, context);
}
finally
{
processFinally(context);
}
return Response.status(Status.OK).build();
}
/**
* Update bitstream metadata. It replace everything on targeted bitstream.
* It can throws WebApplicationException caused by two exceptions:
* SQLException, if there was problem with database. AuthorizeException if
* there was problem with authorization to edit bitstream metadata.
*
* @param bitstreamId
* Id of bistream, wich will be updated.
* @param bitstream
* Bitstream with will be placed. It muset have filled user
* creditials.
* @param headers
* If you want to access to item under logged user into context.
* In headers must be set header "rest-dspace-token" with passed
* token from login method.
* @return Return response codes: OK(200), NOT_FOUND(404) if bitstream does
* not exist and UNAUTHORIZED(401) if user is not allowed to write
* to bitstream.
* @throws WebApplicationException
* It can be thrown by: Error in reading from database. Or
* creating context or with authorization to bitstream.
*/
@PUT
@Path("/{bitstream_id}")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response updateBitstream(@PathParam("bitstream_id") Integer bitstreamId, Bitstream bitstream,
@QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
@QueryParam("xforwarderfor") String xforwarderfor, @Context HttpHeaders headers, @Context HttpServletRequest request)
throws WebApplicationException
{
log.info("Updating bitstream(id=" + bitstreamId + ") metadata.");
org.dspace.core.Context context = null;
try
{
context = createContext(getUser(headers));
org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, org.dspace.core.Constants.WRITE);
writeStats(dspaceBitstream, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwarderfor,
headers, request);
log.trace("Updating bitstream metadata.");
dspaceBitstream.setDescription(bitstream.getDescription());
if (getMimeType(bitstream.getName()) == null)
{
dspaceBitstream.setFormat(BitstreamFormat.findUnknown(context));
}
else
{
dspaceBitstream.setFormat(BitstreamFormat.findByMIMEType(context, getMimeType(bitstream.getName())));
}
dspaceBitstream.setName(bitstream.getName());
Integer sequenceId = bitstream.getSequenceId();
if (sequenceId != null && sequenceId.intValue() != -1)
{
dspaceBitstream.setSequenceID(sequenceId);
}
dspaceBitstream.update();
if (bitstream.getPolicies() != null)
{
Bundle[] bundles = dspaceBitstream.getBundles();
ResourcePolicy[] policies = bitstream.getPolicies();
for (Bundle bundle : bundles)
{
List<org.dspace.authorize.ResourcePolicy> bitstreamsPolicies = bundle.getBitstreamPolicies();
// Remove old bitstream policies
List<org.dspace.authorize.ResourcePolicy> policiesToRemove = new ArrayList<org.dspace.authorize.ResourcePolicy>();
for (org.dspace.authorize.ResourcePolicy policy : bitstreamsPolicies)
{
if (policy.getResourceID() == dspaceBitstream.getID())
{
policiesToRemove.add(policy);
}
}
for (org.dspace.authorize.ResourcePolicy policy : policiesToRemove)
{
bitstreamsPolicies.remove(policy);
}
// Add all new bitstream policies
for (ResourcePolicy policy : policies)
{
org.dspace.authorize.ResourcePolicy dspacePolicy = org.dspace.authorize.ResourcePolicy.create(context);
dspacePolicy.setAction(policy.getActionInt());
dspacePolicy.setGroup(Group.find(context, policy.getGroupId()));
dspacePolicy.setResourceID(dspaceBitstream.getID());
dspacePolicy.setResource(dspaceBitstream);
dspacePolicy.setResourceType(org.dspace.core.Constants.BITSTREAM);
dspacePolicy.setStartDate(policy.getStartDate());
dspacePolicy.setEndDate(policy.getEndDate());
dspacePolicy.setRpDescription(policy.getRpDescription());
dspacePolicy.setRpName(policy.getRpName());
dspacePolicy.update();
bitstreamsPolicies.add(dspacePolicy);
}
bundle.replaceAllBitstreamPolicies(bitstreamsPolicies);
bundle.update();
}
}
context.complete();
}
catch (SQLException e)
{
processException("Could not update bitstream(id=" + bitstreamId + ") metadata, SQLException. Message: " + e, context);
}
catch (AuthorizeException e)
{
processException("Could not update bitstream(id=" + bitstreamId + ") metadata, AuthorizeException. Message: " + e,
context);
}
catch (ContextException e)
{
processException(
"Could not update bitstream(id=" + bitstreamId + ") metadata, ContextException. Message: " + e.getMessage(),
context);
}
finally
{
processFinally(context);
}
log.info("Bitstream metadata(id=" + bitstreamId + ") were successfully updated.");
return Response.ok().build();
}
/**
* Update bitstream data. It change bitstream data by editing database rows.
* It can throw WebApplicationException caused by: SQLException if there was
* problem with database editing or reading, IOException if there was
* problem with reading from inputstream, Exception if there was another
* problem.
*
* @param bitstreamId
* Id of bistream, which will be updated.
* @param is
* Inputstream filled with new data.
* @param headers
* If you want to access to item under logged user into context.
* In headers must be set header "rest-dspace-token" with passed
* token from login method.
* @return Return response if bitstream was updated. Response codes:
* OK(200), NOT_FOUND(404) if id of bitstream was bad. And
* UNAUTHORIZED(401) if user is not allowed to update bitstream.
* @throws WebApplicationException
* This exception can be thrown in this cases: Problem with
* reading or writing to database. Or problem with reading from
* inputstream.
*/
// TODO Change to better logic, without editing database.
@PUT
@Path("/{bitstream_id}/data")
public Response updateBitstreamData(@PathParam("bitstream_id") Integer bitstreamId, InputStream is,
@QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
@QueryParam("xforwarderfor") String xforwarderfor, @Context HttpHeaders headers, @Context HttpServletRequest request)
throws WebApplicationException
{
log.info("Updating bitstream(id=" + bitstreamId + ") data.");
org.dspace.core.Context context = null;
try
{
context = createContext(getUser(headers));
org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, org.dspace.core.Constants.WRITE);
writeStats(dspaceBitstream, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwarderfor,
headers, request);
log.trace("Creating new bitstream.");
int newBitstreamId = BitstreamStorageManager.store(context, is);
log.trace("Looking for table rows of bitstreams.");
TableRow originalBitstreamRow = DatabaseManager.find(context, "Bitstream", bitstreamId);
TableRow bitstream = DatabaseManager.find(context, "Bitstream", newBitstreamId);
log.trace("Changing new internal id with old internal id.");
String internal_id = originalBitstreamRow.getStringColumn("internal_id");
Long size_bytes = originalBitstreamRow.getLongColumn("size_bytes");
originalBitstreamRow.setColumn("internal_id", bitstream.getStringColumn("internal_id"));
originalBitstreamRow.setColumn("size_bytes", bitstream.getLongColumn("size_bytes"));
bitstream.setColumn("internal_id", internal_id);
bitstream.setColumn("size_bytes", size_bytes);
DatabaseManager.update(context, originalBitstreamRow);
BitstreamStorageManager.delete(context, newBitstreamId);
context.complete();
}
catch (SQLException e)
{
processException("Could not update bitstream(id=" + bitstreamId + ") data, SQLException. Message: " + e, context);
}
catch (IOException e)
{
processException("Could not update bitstream(id=" + bitstreamId + ") data, IOException. Message: " + e, context);
}
catch (ContextException e)
{
processException(
"Could not update bitstream(id=" + bitstreamId + ") data, ContextException. Message: " + e.getMessage(),
context);
}
finally
{
processFinally(context);
}
log.info("Bitstream(id=" + bitstreamId + ") data was successfully updated.");
return Response.ok().build();
}
/**
* Delete bitstream from all bundles in dspace. It can throw
* WebApplicationException, which can be caused by three exceptions.
* SQLException if there was problem with reading from database or removing
* from database. AuthorizeException, if user has not permission to delete
* bitstream or file. IOException, if there was problem with file deleting.
*
* @param bitstreamId
* Id of bitsream, which will be deleted.
* @param headers
* If you want to access to item under logged user into context.
* In headers must be set header "rest-dspace-token" with passed
* token from login method.
* @return Return response codes: OK(200), NOT_FOUND(404) if bitstream of
* that id does not exist and UNAUTHORIZED(401) if user is not
* allowed to delete bitstream.
* @throws WebApplicationException
* It can be throw when was problem with reading or editting
* database. Or problem with file deleting. Or problem with
* authorization to bitstream and bundles. Or problem with
* creating context.
*/
@DELETE
@Path("/{bitstream_id}")
public Response deleteBitstream(@PathParam("bitstream_id") Integer bitstreamId, @QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent, @QueryParam("xforwarderfor") String xforwarderfor,
@Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException
{
log.info("Deleting bitstream(id=" + bitstreamId + ").");
org.dspace.core.Context context = null;
try
{
context = createContext(getUser(headers));
org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, org.dspace.core.Constants.DELETE);
writeStats(dspaceBitstream, UsageEvent.Action.DELETE, user_ip, user_agent, xforwarderfor,
headers, request);
log.trace("Deleting bitstream from all bundles.");
for (org.dspace.content.Bundle bundle : dspaceBitstream.getBundles())
{
org.dspace.content.Bundle.find(context, bundle.getID()).removeBitstream(dspaceBitstream);
}
context.complete();
}
catch (SQLException e)
{
processException("Could not delete bitstream(id=" + bitstreamId + "), SQLException. Message: " + e, context);
}
catch (AuthorizeException e)
{
processException("Could not delete bitstream(id=" + bitstreamId + "), AuthorizeException. Message: " + e, context);
}
catch (IOException e)
{
processException("Could not delete bitstream(id=" + bitstreamId + "), IOException. Message: " + e, context);
}
catch (ContextException e)
{
processException("Could not delete bitstream(id=" + bitstreamId + "), ContextException. Message:" + e.getMessage(),
context);
}
finally
{
processFinally(context);
}
log.info("Bitstream(id=" + bitstreamId + ") was successfully deleted.");
return Response.ok().build();
}
/**
* Delete policy.
*
* @param bitstreamId
* Id of bitstream in dspace, which policy will be deleted.
* @param policyId
* Id of policy which will be deleted.
* @param headers
* If you want to access to item under logged user into context.
* In headers must be set header "rest-dspace-token" with passed
* token from login method.
* @return It returns Ok, if was all ok. Otherwise status code 500.
*/
@DELETE
@Path("/{bitstream_id}/policy/{policy_id}")
public javax.ws.rs.core.Response deleteBitstreamPolicy(@PathParam("bitstream_id") Integer bitstreamId,
@PathParam("policy_id") Integer policyId, @Context HttpHeaders headers)
{
log.info("Deleting bitstream(id=" + bitstreamId + ") READ policy(id=" + policyId + ").");
org.dspace.core.Context context = null;
try
{
context = createContext(getUser(headers));
org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId, org.dspace.core.Constants.READ);
Bundle[] bundles = dspaceBitstream.getBundles();
for (Bundle bundle : bundles)
{
List<org.dspace.authorize.ResourcePolicy> bitstreamsPolicies = bundle.getBitstreamPolicies();
for (org.dspace.authorize.ResourcePolicy policy : bitstreamsPolicies)
{
if (policy.getID() == policyId.intValue())
{
bitstreamsPolicies.remove(policy);
break;
}
}
bundle.replaceAllBitstreamPolicies(bitstreamsPolicies);
bundle.update();
}
context.complete();
log.trace("Policy for bitsream(id=" + bitstreamId + ") was successfully added.");
}
catch (SQLException e)
{
processException("Someting went wrong while deleting READ policy(id=" + policyId + ") to bitstream(id=" + bitstreamId
+ "), SQLException! Message: " + e, context);
}
catch (ContextException e)
{
processException("Someting went wrong while deleting READ policy(id=" + policyId + ") to bitstream(id=" + bitstreamId
+ "), ContextException. Message: " + e.getMessage(), context);
}
catch (AuthorizeException e)
{
processException("Someting went wrong while deleting READ policy(id=" + policyId + ") to bitstream(id=" + bitstreamId
+ "), AuthorizeException! Message: " + e, context);
}
finally
{
processFinally(context);
}
return Response.status(Status.OK).build();
}
/**
* Return type of file in MIME, by file extension.
*
* @param name
* Name of file.
* @return String filled with type of file in MIME style.
*/
static String getMimeType(String name)
{
return URLConnection.guessContentTypeFromName(name);
}
/**
* Find bitstream from DSpace database. It is encapsulation of method
* org.dspace.content.Bitstream.find with checking if item exist and if user
* logged into context has permission to do passed action.
*
* @param context
* Context of actual logged user.
* @param id
* Id of bitstream in DSpace.
* @param action
* Constant from org.dspace.core.Constants.
* @return It returns DSpace bitstream.
* @throws WebApplicationException
* Is thrown when item with passed id is not exists and if user
* has no permission to do passed action.
*/
private org.dspace.content.Bitstream findBitstream(org.dspace.core.Context context, int id, int action)
throws WebApplicationException
{
org.dspace.content.Bitstream bitstream = null;
try
{
bitstream = org.dspace.content.Bitstream.find(context, id);
if ((bitstream == null) || (bitstream.getParentObject() == null))
{
context.abort();
log.warn("Bitstream(id=" + id + ") was not found!");
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
else if (!AuthorizeManager.authorizeActionBoolean(context, bitstream, action))
{
context.abort();
if (context.getCurrentUser() != null)
{
log.error("User(" + context.getCurrentUser().getEmail() + ") has not permission to "
+ getActionString(action) + " bitstream!");
}
else
{
log.error("User(anonymous) has not permission to " + getActionString(action) + " bitsteam!");
}
throw new WebApplicationException(Response.Status.UNAUTHORIZED); 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);
} finally {
if(context != null) {
try {
context.complete();
} catch (SQLException e) {
log.error(e.getMessage() + " occurred while trying to close");
}
}
} }
catch (SQLException e)
{
processException("Something get wrong while finding bitstream. SQLException, Message:" + e, context);
}
return bitstream;
} }
private void writeStats(org.dspace.core.Context context, 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);
}
}
} }

View File

@@ -7,149 +7,767 @@
*/ */
package org.dspace.rest; package org.dspace.rest;
import java.io.IOException;
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.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
/* import javax.servlet.http.HttpServletRequest;
The "Path" annotation indicates the URI this class will be available at relative to your base URL. For import javax.ws.rs.Consumes;
example, if this web-app is launched at localhost using a context of "hello" and no URL pattern is defined import javax.ws.rs.DELETE;
in the web.xml servlet mapping section, then the web service will be available at: import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
http://localhost:8080/<webapp>/collections import org.apache.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.browse.BrowseException;
import org.dspace.rest.common.Collection;
import org.dspace.rest.common.Item;
import org.dspace.rest.common.MetadataEntry;
import org.dspace.rest.exceptions.ContextException;
import org.dspace.usage.UsageEvent;
/**
* This class provides all CRUD operation over collections.
*
* @author Rostislav Novak (Computing and Information Centre, CTU in Prague)
*/ */
@Path("/collections") @Path("/collections")
public class CollectionsResource { public class CollectionsResource extends Resource
{
private static Logger log = Logger.getLogger(CollectionsResource.class); private static Logger log = Logger.getLogger(CollectionsResource.class);
@javax.ws.rs.core.Context ServletContext servletContext; /**
* Return instance of collection with passed id. You can add more properties
private static final boolean writeStatistics; * through expand parameter.
*
static{ * @param collectionId
writeStatistics=ConfigurationManager.getBooleanProperty("rest","stats",false); * Id of collection in DSpace.
} * @param expand
* String in which is what you want to add to returned instance
@GET * of collection. Options are: "all", "parentCommunityList",
@Path("/") * "parentCommunity", "items", "license" and "logo". If you want
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) * to use multiple options, it must be separated by commas.
public org.dspace.rest.common.Collection[] list(@QueryParam("expand") String expand, @QueryParam("limit") @DefaultValue("100") Integer limit, @QueryParam("offset") @DefaultValue("0") Integer offset) { * @param limit
org.dspace.core.Context context = null; * Limit value for items in list in collection. Default value is
try { * 100.
context = new org.dspace.core.Context(); * @param offset
* Offset of start index in list of items of collection. Default
org.dspace.content.Collection[] collections; * value is 0.
* @param headers
//Only support paging if limit/offset are 0 or positive values. * If you want to access to collection under logged user into
if(limit != null && limit >= 0 && offset != null && offset >= 0) { * context. In headers must be set header "rest-dspace-token"
collections = org.dspace.content.Collection.findAll(context, limit, offset); * with passed token from login method.
} else { * @return Return instance of collection. It can also return status code
collections = org.dspace.content.Collection.findAll(context); * NOT_FOUND(404) if id of collection is incorrect or status code
} * UNATHORIZED(401) if user has no permission to read collection.
* @throws WebApplicationException
ArrayList<org.dspace.rest.common.Collection> collectionArrayList = new ArrayList<org.dspace.rest.common.Collection>(); * It is thrown when was problem with database reading
for(org.dspace.content.Collection collection : collections) { * (SQLException) or problem with creating
if(AuthorizeManager.authorizeActionBoolean(context, collection, org.dspace.core.Constants.READ)) { * context(ContextException). It is thrown by NOT_FOUND and
org.dspace.rest.common.Collection restCollection = new org.dspace.rest.common.Collection(collection, null, context, limit, offset); * UNATHORIZED status codes, too.
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);
} finally {
if(context != null) {
try {
context.complete();
} catch (SQLException e) {
log.error(e.getMessage() + " occurred while trying to close");
}
}
}
}
@GET @GET
@Path("/{collection_id}") @Path("/{collection_id}")
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public org.dspace.rest.common.Collection getCollection(@PathParam("collection_id") Integer collection_id, @QueryParam("expand") String expand, public org.dspace.rest.common.Collection getCollection(@PathParam("collection_id") Integer collectionId,
@QueryParam("limit") @DefaultValue("100") Integer limit, @QueryParam("offset") @DefaultValue("0") Integer offset, @QueryParam("expand") String expand, @QueryParam("limit") @DefaultValue("100") Integer limit,
@QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent, @QueryParam("xforwarderfor") String xforwarderfor, @QueryParam("offset") @DefaultValue("0") Integer offset, @QueryParam("userIP") String user_ip,
@Context HttpHeaders headers, @Context HttpServletRequest request) { @QueryParam("userAgent") String user_agent, @QueryParam("xforwarderfor") String xforwarderfor,
org.dspace.core.Context context = null; @Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException
try { {
context = new org.dspace.core.Context();
org.dspace.content.Collection collection = org.dspace.content.Collection.find(context, collection_id); log.info("Reading collection(id=" + collectionId + ").");
if(AuthorizeManager.authorizeActionBoolean(context, collection, org.dspace.core.Constants.READ)) { org.dspace.core.Context context = null;
if(writeStatistics){ Collection collection = null;
writeStats(context, collection_id, user_ip, user_agent, xforwarderfor, headers, request);
} try
return new org.dspace.rest.common.Collection(collection, expand, context, limit, offset); {
} else { context = createContext(getUser(headers));
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
org.dspace.content.Collection dspaceCollection = findCollection(context, collectionId, org.dspace.core.Constants.READ);
writeStats(dspaceCollection, UsageEvent.Action.VIEW, user_ip, user_agent, xforwarderfor,
headers, request);
collection = new Collection(dspaceCollection, expand, context, limit, offset);
context.complete();
}
catch (SQLException e)
{
processException("Could not read collection(id=" + collectionId + "), SQLException. Message: " + e, context);
}
catch (ContextException e)
{
processException("Could not read collection(id=" + collectionId + "), ContextException. Message: " + e.getMessage(),
context);
}
finally
{
processFinally(context);
}
log.trace("Collection(id=" + collectionId + ") has been successfully read.");
return collection;
}
/**
* Return array of all collections in DSpace. You can add more properties
* through expand parameter.
*
* @param expand
* String in which is what you want to add to returned instance
* of collection. Options are: "all", "parentCommunityList",
* "parentCommunity", "items", "license" and "logo". If you want
* to use multiple options, it must be separated by commas.
* @param limit
* Limit value for items in list in collection. Default value is
* 100.
* @param offset
* Offset of start index in list of items of collection. Default
* value is 0.
* @param headers
* If you want to access to collections under logged user into
* context. In headers must be set header "rest-dspace-token"
* with passed token from login method.
* @return Return array of collection, on which has logged user permission
* to view.
* @throws WebApplicationException
* It is thrown when was problem with database reading
* (SQLException) or problem with creating
* context(ContextException).
*/
@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public org.dspace.rest.common.Collection[] getCollections(@QueryParam("expand") String expand,
@QueryParam("limit") @DefaultValue("100") Integer limit, @QueryParam("offset") @DefaultValue("0") Integer offset,
@QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
@QueryParam("xforwarderfor") String xforwarderfor, @Context HttpHeaders headers, @Context HttpServletRequest request)
throws WebApplicationException
{
log.info("Reading all collections.(offset=" + offset + ",limit=" + limit + ")");
org.dspace.core.Context context = null;
List<Collection> collections = new ArrayList<Collection>();
try
{
context = createContext(getUser(headers));
if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0)))
{
log.warn("Paging was badly set.");
limit = 100;
offset = 0;
} }
} catch (SQLException e) {
log.error(e.getMessage()); org.dspace.content.Collection[] dspaceCollections = org.dspace.content.Collection.findAll(context, limit, offset);
throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); for(org.dspace.content.Collection dspaceCollection : dspaceCollections)
} finally { {
if(context != null) { if (AuthorizeManager.authorizeActionBoolean(context, dspaceCollection, org.dspace.core.Constants.READ))
try { {
context.complete(); Collection collection = new org.dspace.rest.common.Collection(dspaceCollection, null, context, limit,
} catch (SQLException e) { offset);
log.error(e.getMessage() + " occurred while trying to close"); collections.add(collection);
writeStats(dspaceCollection, UsageEvent.Action.VIEW, user_ip, user_agent,
xforwarderfor, headers, request);
} }
} }
context.complete();
} }
catch (SQLException e)
{
processException("Something went wrong while reading collections from database. Message: " + e, context);
}
catch (ContextException e)
{
processException("Something went wrong while reading collections, ContextError. Message: " + e.getMessage(), context);
}
finally
{
processFinally(context);
}
log.trace("All collections were successfully read.");
return collections.toArray(new org.dspace.rest.common.Collection[0]);
}
/**
* Return array of items in collection. You can add more properties to items
* with expand parameter.
*
* @param collectionId
* Id of collection in DSpace.
* @param expand
* String which define, what additional properties will be in
* returned item. Options are separeted by commas and are: "all",
* "metadata", "parentCollection", "parentCollectionList",
* "parentCommunityList" and "bitstreams".
* @param limit
* Limit value for items in array. Default value is 100.
* @param offset
* Offset of start index in array of items of collection. Default
* value is 0.
* @param headers
* If you want to access to collection under logged user into
* context. In headers must be set header "rest-dspace-token"
* with passed token from login method.
* @return Return array of items, on which has logged user permission to
* read. It can also return status code NOT_FOUND(404) if id of
* collection is incorrect or status code UNATHORIZED(401) if user
* has no permission to read collection.
* @throws WebApplicationException
* It is thrown when was problem with database reading
* (SQLException) or problem with creating
* context(ContextException). It is thrown by NOT_FOUND and
* UNATHORIZED status codes, too.
*/
@GET
@Path("/{collection_id}/items")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public org.dspace.rest.common.Item[] getCollectionItems(@PathParam("collection_id") Integer collectionId,
@QueryParam("expand") String expand, @QueryParam("limit") @DefaultValue("100") Integer limit,
@QueryParam("offset") @DefaultValue("0") Integer offset, @QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent, @QueryParam("xforwarderfor") String xforwarderfor,
@Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException
{
log.info("Reading collection(id=" + collectionId + ") items.");
org.dspace.core.Context context = null;
List<Item> items = null;
try
{
context = createContext(getUser(headers));
org.dspace.content.Collection dspaceCollection = findCollection(context, collectionId, org.dspace.core.Constants.READ);
writeStats(dspaceCollection, UsageEvent.Action.VIEW, user_ip, user_agent, xforwarderfor,
headers, request);
items = new ArrayList<Item>();
org.dspace.content.ItemIterator dspaceItems = dspaceCollection.getItems();
for (int i = 0; (dspaceItems.hasNext()) && (i < (limit + offset)); i++)
{
if (i >= offset)
{
org.dspace.content.Item dspaceItem = dspaceItems.next();
if (AuthorizeManager.authorizeActionBoolean(context, dspaceItem, org.dspace.core.Constants.READ))
{
items.add(new Item(dspaceItem, expand, context));
writeStats(dspaceItem, UsageEvent.Action.VIEW, user_ip, user_agent, xforwarderfor,
headers, request);
}
}
}
context.complete();
}
catch (SQLException e)
{
processException("Could not read collection items, SQLException. Message: " + e, context);
}
catch (ContextException e)
{
processException("Could not read collection items, ContextException. Message: " + e.getMessage(), context);
}
finally
{
processFinally(context);
}
log.trace("All items in collection(id=" + collectionId + ") were successfully read.");
return items.toArray(new Item[0]);
}
/**
* Create item in collection. Item can be without filled metadata.
*
* @param collectionId
* Id of collection in which will be item created.
* @param item
* Item filled only with metadata, other variables are ignored.
* @param headers
* If you want to access to collection under logged user into
* context. In headers must be set header "rest-dspace-token"
* with passed token from login method.
* @return Return status code with item. Return status (OK)200 if item was
* created. NOT_FOUND(404) if id of collection does not exists.
* UNAUTHORIZED(401) if user have not permission to write items in
* collection.
* @throws WebApplicationException
* It is thrown when was problem with database reading or
* writing (SQLException) or problem with creating
* context(ContextException) or problem with authorization to
* collection or IOException or problem with index item into
* browse index. It is thrown by NOT_FOUND and UNATHORIZED
* status codes, too.
*
*/
@POST
@Path("/{collection_id}/items")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Item addCollectionItem(@PathParam("collection_id") Integer collectionId, Item item,
@QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
@QueryParam("xforwarderfor") String xforwarderfor, @Context HttpHeaders headers, @Context HttpServletRequest request)
throws WebApplicationException
{
log.info("Create item in collection(id=" + collectionId + ").");
org.dspace.core.Context context = null;
Item returnItem = null;
try
{
context = createContext(getUser(headers));
org.dspace.content.Collection dspaceCollection = findCollection(context, collectionId,
org.dspace.core.Constants.WRITE);
writeStats(dspaceCollection, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwarderfor,
headers, request);
log.trace("Creating item in collection(id=" + collectionId + ").");
org.dspace.content.WorkspaceItem workspaceItem = org.dspace.content.WorkspaceItem.create(context, dspaceCollection,
false);
org.dspace.content.Item dspaceItem = workspaceItem.getItem();
log.trace("Adding metadata to item(id=" + dspaceItem.getID() + ").");
if (item.getMetadata() != null)
{
for (MetadataEntry entry : item.getMetadata())
{
String data[] = mySplit(entry.getKey());
dspaceItem.addMetadata(data[0], data[1], data[2], entry.getLanguage(), entry.getValue());
}
}
workspaceItem.update();
// Index item to browse.
org.dspace.browse.IndexBrowse browse = new org.dspace.browse.IndexBrowse();
browse.indexItem(dspaceItem);
log.trace("Installing item to collection(id=" + collectionId + ").");
dspaceItem = org.dspace.content.InstallItem.installItem(context, workspaceItem);
returnItem = new Item(dspaceItem, "", context);
context.complete();
}
catch (SQLException e)
{
processException("Could not add item into collection(id=" + collectionId + "), SQLException. Message: " + e, context);
}
catch (AuthorizeException e)
{
processException("Could not add item into collection(id=" + collectionId + "), AuthorizeException. Message: " + e,
context);
}
catch (IOException e)
{
processException("Could not add item into collection(id=" + collectionId + "), IOException. Message: " + e, context);
}
catch (BrowseException e)
{
processException("Could not add item into browse index, BrowseException. Message: " + e, context);
}
catch (ContextException e)
{
processException(
"Could not add item into collection(id=" + collectionId + "), ContextException. Message: " + e.getMessage(),
context);
}
finally
{
processFinally(context);
}
log.info("Item successfully created in collection(id=" + collectionId + "). Item handle=" + returnItem.getHandle());
return returnItem;
}
/**
* Update collection. It replace all properties.
*
* @param collectionId
* Id of collection in DSpace.
* @param collection
* Collection which will replace properties of actual collection.
* @param headers
* If you want to access to collection under logged user into
* context. In headers must be set header "rest-dspace-token"
* with passed token from login method.
* @return Return response 200 if was everything all right. Otherwise 400
* when id of community was incorrect or 401 if was problem with
* permission to write into collection.
* @throws WebApplicationException
* It is thrown when was problem with database reading or
* writing. Or problem with authorization to collection. Or
* problem with creating context.
*/
@PUT
@Path("/{collection_id}")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response updateCollection(@PathParam("collection_id") Integer collectionId,
org.dspace.rest.common.Collection collection, @QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent, @QueryParam("xforwarderfor") String xforwarderfor,
@Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException
{
log.info("Updating collection(id=" + collectionId + ").");
org.dspace.core.Context context = null;
try
{
context = createContext(getUser(headers));
org.dspace.content.Collection dspaceCollection = findCollection(context, collectionId,
org.dspace.core.Constants.WRITE);
writeStats(dspaceCollection, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwarderfor,
headers, request);
dspaceCollection.setMetadata("name", collection.getName());
dspaceCollection.setLicense(collection.getLicense());
// dspaceCollection.setLogo(collection.getLogo()); // TODO Add this option.
dspaceCollection.setMetadata(org.dspace.content.Collection.COPYRIGHT_TEXT, collection.getCopyrightText());
dspaceCollection.setMetadata(org.dspace.content.Collection.INTRODUCTORY_TEXT, collection.getIntroductoryText());
dspaceCollection.setMetadata(org.dspace.content.Collection.SHORT_DESCRIPTION, collection.getShortDescription());
dspaceCollection.setMetadata(org.dspace.content.Collection.SIDEBAR_TEXT, collection.getSidebarText());
dspaceCollection.update();
context.complete();
}
catch (ContextException e)
{
processException("Could not update collection(id=" + collectionId + "), ContextEception. Message: " + e.getMessage(),
context);
}
catch (SQLException e)
{
processException("Could not update collection(id=" + collectionId + "), SQLException. Message: " + e, context);
}
catch (AuthorizeException e)
{
processException("Could not update collection(id=" + collectionId + "), AuthorizeException. Message: " + e, context);
}
finally
{
processFinally(context);
}
log.info("Collection(id=" + collectionId + ") successfully updated.");
return Response.ok().build();
}
/**
* Delete collection.
*
* @param collectionId
* Id of collection which will be deleted.
* @param headers
* If you want to access to collection under logged user into
* context. In headers must be set header "rest-dspace-token"
* with passed token from login method.
* @return Return response code OK(200) if was everything all right.
* Otherwise return NOT_FOUND(404) if was id of community or
* collection incorrect. Or (UNAUTHORIZED)401 if was problem with
* permission to community or collection.
* @throws WebApplicationException
* It is throw when was problem with creating context or problem
* with database reading or writing. Or problem with deleting
* collection caused by IOException or authorization.
*/
@DELETE
@Path("/{collection_id}")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response deleteCollection(@PathParam("collection_id") Integer collectionId, @QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent, @QueryParam("xforwarderfor") String xforwarderfor,
@Context HttpHeaders headers, @Context HttpServletRequest request) throws WebApplicationException
{
log.info("Delete collection(id=" + collectionId + ").");
org.dspace.core.Context context = null;
try
{
context = createContext(getUser(headers));
org.dspace.content.Collection dspaceCollection = findCollection(context, collectionId,
org.dspace.core.Constants.DELETE);
writeStats(dspaceCollection, UsageEvent.Action.REMOVE, user_ip, user_agent, xforwarderfor,
headers, request);
org.dspace.content.Community community = (org.dspace.content.Community) dspaceCollection.getParentObject();
community.removeCollection(dspaceCollection);
context.complete();
}
catch (ContextException e)
{
processException(
"Could not delete collection(id=" + collectionId + "), ContextExcpetion. Message: " + e.getMessage(), context);
}
catch (SQLException e)
{
processException("Could not delete collection(id=" + collectionId + "), SQLException. Message: " + e, context);
}
catch (AuthorizeException e)
{
processException("Could not delete collection(id=" + collectionId + "), AuthorizeException. Message: " + e, context);
}
catch (IOException e)
{
processException("Could not delete collection(id=" + collectionId + "), IOException. Message: " + e, context);
}
finally
{
processFinally(context);
}
log.info("Collection(id=" + collectionId + ") was successfully deleted.");
return Response.ok().build();
}
/**
* Delete item in collection.
*
* @param collectionId
* Id of collection which will be deleted.
*
* @param itemId
* Id of item in colletion.
* @return It returns status code: OK(200). NOT_FOUND(404) if item or
* collection was not found, UNAUTHORIZED(401) if user is not
* allowed to delete item or permission to write into collection.
* @throws WebApplicationException
* It can be thrown by: SQLException, when was problem with
* database reading or writting. AuthorizeException, when was
* problem with authorization to item or collection.
* IOException, when was problem with removing item.
* ContextException, when was problem with creating context of
* DSpace.
*/
@DELETE
@Path("/{collection_id}/items/{item_id}")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response deleteCollectionItem(@PathParam("collection_id") Integer collectionId, @PathParam("item_id") Integer itemId,
@QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
@QueryParam("xforwarderfor") String xforwarderfor, @Context HttpHeaders headers, @Context HttpServletRequest request)
throws WebApplicationException
{
log.info("Delete item(id=" + itemId + ") in collection(id=" + collectionId + ").");
org.dspace.core.Context context = null;
try
{
context = createContext(getUser(headers));
org.dspace.content.Collection dspaceCollection = findCollection(context, collectionId,
org.dspace.core.Constants.WRITE);
org.dspace.content.Item item = null;
org.dspace.content.ItemIterator dspaceItems = dspaceCollection.getItems();
while (dspaceItems.hasNext())
{
org.dspace.content.Item dspaceItem = dspaceItems.next();
if (dspaceItem.getID() == itemId)
{
item = dspaceItem;
}
}
if (item == null)
{
context.abort();
log.warn("Item(id=" + itemId + ") was not found!");
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
else if (!AuthorizeManager.authorizeActionBoolean(context, item, org.dspace.core.Constants.REMOVE))
{
context.abort();
if (context.getCurrentUser() != null)
{
log.error("User(" + context.getCurrentUser().getEmail() + ") has not permission to delete item!");
}
else
{
log.error("User(anonymous) has not permission to delete item!");
}
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}
writeStats(dspaceCollection, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwarderfor,
headers, request);
writeStats(item, UsageEvent.Action.REMOVE, user_ip, user_agent, xforwarderfor, headers, request);
dspaceCollection.removeItem(item);
context.complete();
}
catch (ContextException e)
{
processException("Could not delete item(id=" + itemId + ") in collection(id=" + collectionId
+ "), ContextException. Message: " + e.getMessage(), context);
}
catch (SQLException e)
{
processException("Could not delete item(id=" + itemId + ") in collection(id=" + collectionId
+ "), SQLException. Message: " + e, context);
}
catch (AuthorizeException e)
{
processException("Could not delete item(id=" + itemId + ") in collection(id=" + collectionId
+ "), AuthorizeException. Message: " + e, context);
}
catch (IOException e)
{
processException("Could not delete item(id=" + itemId + ") in collection(id=" + collectionId
+ "), IOException. Message: " + e, context);
}
finally
{
processFinally(context);
}
log.info("Item(id=" + itemId + ") in collection(id=" + collectionId + ") was successfully deleted.");
return Response.ok().build();
}
/**
* Search for first collection with passed name.
*
* @param name
* Name of collection.
* @param headers
* If you want to access to collection under logged user into
* context. In headers must be set header "rest-dspace-token"
* with passed token from login method.
* @return It returns null if collection was not found. Otherwise returns
* first founded collection.
* @throws WebApplicationException
*/
@POST
@Path("/find-collection")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Collection findCollectionByName(String name, @Context HttpHeaders headers) throws WebApplicationException
{
log.info("Searching for first collection with name=" + name + ".");
org.dspace.core.Context context = null;
Collection collection = null;
try
{
context = createContext(getUser(headers));
org.dspace.content.Collection[] dspaceCollections;
dspaceCollections = org.dspace.content.Collection.findAll(context);
for (org.dspace.content.Collection dspaceCollection : dspaceCollections)
{
if (AuthorizeManager.authorizeActionBoolean(context, dspaceCollection, org.dspace.core.Constants.READ))
{
if (dspaceCollection.getName().equals(name))
{
collection = new Collection(dspaceCollection, "", context, 100, 0);
break;
}
}
}
context.complete();
}
catch (SQLException e)
{
processException("Something went wrong while searching for collection(name=" + name + ") from database. Message: "
+ e, context);
}
catch (ContextException e)
{
processException("Something went wrong while searching for collection(name=" + name + "), ContextError. Message: "
+ e.getMessage(), context);
}
finally
{
processFinally(context);
}
if (collection == null)
{
log.info("Collection was not found.");
}
else
{
log.info("Collection was found with id(" + collection.getId() + ").");
}
return collection;
}
/**
* Find collection from DSpace database. It is encapsulation of method
* org.dspace.content.Collection.find with checking if item exist and if
* user logged into context has permission to do passed action.
*
* @param context
* Context of actual logged user.
* @param id
* Id of collection in DSpace.
* @param action
* Constant from org.dspace.core.Constants.
* @return It returns DSpace collection.
* @throws WebApplicationException
* Is thrown when item with passed id is not exists and if user
* has no permission to do passed action.
*/
private org.dspace.content.Collection findCollection(org.dspace.core.Context context, int id, int action)
throws WebApplicationException
{
org.dspace.content.Collection collection = null;
try
{
collection = org.dspace.content.Collection.find(context, id);
if (collection == null)
{
context.abort();
log.warn("Collection(id=" + id + ") was not found!");
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
else if (!AuthorizeManager.authorizeActionBoolean(context, collection, action))
{
context.abort();
if (context.getCurrentUser() != null)
{
log.error("User(" + context.getCurrentUser().getEmail() + ") has not permission to "
+ getActionString(action) + " collection!");
}
else
{
log.error("User(anonymous) has not permission to " + getActionString(action) + " collection!");
}
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}
}
catch (SQLException e)
{
processException("Something get wrong while finding collection(id=" + id + "). SQLException, Message: " + e, context);
}
return collection;
} }
private void writeStats(org.dspace.core.Context context, 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);
}
}
} }

View File

@@ -32,14 +32,18 @@ import java.sql.SQLException;
@Path("/handle") @Path("/handle")
public class HandleResource { public class HandleResource {
private static Logger log = Logger.getLogger(HandleResource.class); private static Logger log = Logger.getLogger(HandleResource.class);
private static org.dspace.core.Context context;
@GET @GET
@Path("/{prefix}/{suffix}") @Path("/{prefix}/{suffix}")
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @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) { public org.dspace.rest.common.DSpaceObject getObject(@PathParam("prefix") String prefix, @PathParam("suffix") String suffix, @QueryParam("expand") String expand) {
org.dspace.core.Context context = null;
try { try {
context = new org.dspace.core.Context(); 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); org.dspace.content.DSpaceObject dso = HandleManager.resolveToObject(context, prefix + "/" + suffix);
if(dso == null) { if(dso == null) {
@@ -64,14 +68,6 @@ public class HandleResource {
} catch (SQLException e) { } catch (SQLException e) {
log.error(e.getMessage()); log.error(e.getMessage());
throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
} finally {
if(context != null) {
try {
context.complete();
} catch (SQLException e) {
log.error(e.getMessage() + " occurred while trying to close");
}
}
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,292 @@
/**
* 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 java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import org.apache.log4j.Logger;
import org.dspace.content.DSpaceObject;
import org.dspace.core.ConfigurationManager;
import org.dspace.eperson.EPerson;
import org.dspace.rest.exceptions.ContextException;
import org.dspace.usage.UsageEvent;
import org.dspace.utils.DSpace;
/**
* Superclass of all resource class in REST api. It has methods for creating
* context, write statistics, process exception, splitting key of metadata,
* string representation of action and method for getting user from header.
*
* @author Rostislav Novak (Computing and Information Centre, CTU in Prague)
*
*/
public class Resource
{
private static Logger log = Logger.getLogger(Resource.class);
private static final boolean writeStatistics;
static
{
writeStatistics = ConfigurationManager.getBooleanProperty("rest", "stats", false);
}
/**
* Create context to work with DSpace database. It can create context
* without logged user (parameter user is null) or with. It can throws
* WebApplicationException caused by: SQLException, if there was problem
* with reading from database. AuthorizeException, if there was problem with
* authorization to read form database. And Exception, if there was some
* problem with creating context.
*
* @param person
* User which will be logged in context.
* @return New created context with logged user if user was not null.
* Otherwise, without logged user.
* @throws ContextException
* Throw if was problem to create context. It can be caused by
* SQLException, error in creating context or find user to log
* in. Or can be caused by AuthorizeException if was problem to
* authorize to find user.
*/
protected static org.dspace.core.Context createContext(EPerson person) throws ContextException
{
org.dspace.core.Context context = null;
try
{
context = new org.dspace.core.Context();
context.getDBConnection().setAutoCommit(false); // Disable autocommit.
if (person != null)
{
context.setCurrentUser(person);
}
return context;
}
catch (SQLException e)
{
if ((context != null) && (context.isValid()))
{
context.abort();
}
throw new ContextException("Could not create context, SQLException. Message: " + e, e);
}
}
/**
* It write statistic about using REST api.
* @param dspaceObject
* Object of DSpace which is performed.
* @param action
* What action is performed with object.
* @param user_ip
* @param user_agent
* @param xforwarderfor
* @param headers
* @param request
*/
protected void writeStats(DSpaceObject dspaceObject, UsageEvent.Action action,
String user_ip, String user_agent, String xforwarderfor, HttpHeaders headers, HttpServletRequest request)
{
if (!writeStatistics)
{
return;
}
org.dspace.core.Context context = null;
try
{
context = createContext(getUser(headers));
if ((user_ip == null) || (user_ip.length() == 0))
{
new DSpace().getEventService().fireEvent(new UsageEvent(action, request, context, dspaceObject));
}
else
{
new DSpace().getEventService().fireEvent(
new UsageEvent(action, user_ip, user_agent, xforwarderfor, context, dspaceObject));
}
log.debug("fired event");
context.complete();
}
catch (SQLException e)
{
if ((context != null) && (context.isValid()))
{
context.abort();
}
log.error("Could not write usageEvent, SQLException. Message: " + e);
}
catch (ContextException e)
{
log.error("Could not write usageEvent, ContextException. Message: " + e.getMessage());
}
finally
{
if ((context != null) && (context.isValid()))
{
context.abort();
log.error("Something get wrong. Aborting context in finally statement.");
}
}
}
/**
* Process exception, print message to logger error stream and abort DSpace
* context.
*
* @param message
* Message, which will be printed to error stream.
* @param context
* Context which must be aborted.
* @throws WebApplicationException
* This exception is throw for user of REST api.
*/
protected static void processException(String message, org.dspace.core.Context context) throws WebApplicationException
{
if ((context != null) && (context.isValid()))
{
context.abort();
}
log.error(message);
throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
}
/**
* Process finally statement. It will print message to logger error stream
* and abort DSpace context, if was not properly ended.
*
* @param context
* Context which must be aborted.
* @throws WebApplicationException
* This exception is throw for user of REST api.
*/
protected void processFinally(org.dspace.core.Context context) throws WebApplicationException
{
if ((context != null) && (context.isValid()))
{
context.abort();
log.error("Something get wrong. Aborting context in finally statement.");
throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
}
}
/**
* Split string with regex ".".
*
* @param key
* String which will be splitted.
* @return String array filed with separated string.
*/
protected String[] mySplit(String key)
{
ArrayList<String> list = new ArrayList<String>();
int prev = 0;
for (int i = 0; i < key.length(); i++)
{
if (key.charAt(i) == '.')
{
list.add(key.substring(prev, i));
prev = i + 1;
}
else if (i + 1 == key.length())
{
list.add(key.substring(prev, i + 1));
}
}
if (list.size() == 2)
{
list.add(null);
}
return list.toArray(new String[0]);
}
/**
* Return string representation of values
* org.dspace.core.Constants.{READ,WRITE,DELETE}.
*
* @param action
* Constant from org.dspace.core.Constants.*
* @return String representation. read or write or delete.
*/
protected String getActionString(int action)
{
String actionStr;
switch (action)
{
case org.dspace.core.Constants.READ:
actionStr = "read";
break;
case org.dspace.core.Constants.WRITE:
actionStr = "write";
break;
case org.dspace.core.Constants.DELETE:
actionStr = "delete";
break;
case org.dspace.core.Constants.REMOVE:
actionStr = "remove";
break;
case org.dspace.core.Constants.ADD:
actionStr = "add";
break;
default:
actionStr = "(?action?)";
break;
}
return actionStr;
}
/**
* Return EPerson based on stored token in headers under
* "rest-dspace-token".
*
* @param headers
* Only must have "rest-api-token" for successfull return of
* user.
* @return Return EPerson logged under token in headers. If token was wrong
* or header rest-dspace-token was missing, returns null.
*/
protected static EPerson getUser(HttpHeaders headers)
{
List<String> list = headers.getRequestHeader(TokenHolder.TOKEN_HEADER);
String token = null;
if ((list != null) && (list.size() > 0))
{
token = list.get(0);
return TokenHolder.getEPerson(token);
}
return null;
}
protected static String getToken(HttpHeaders headers) {
List<String> list = headers.getRequestHeader(TokenHolder.TOKEN_HEADER);
String token = null;
if ((list != null) && (list.size() > 0))
{
token = list.get(0);
return token;
}
return null;
}
}

View File

@@ -7,39 +7,229 @@
*/ */
package org.dspace.rest; package org.dspace.rest;
import java.io.UnsupportedEncodingException;
import java.sql.SQLException;
import java.util.List;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
/* import org.apache.log4j.Logger;
Root of API, should have documentation on where to find the other resources. import org.dspace.authorize.AuthorizeException;
import org.dspace.eperson.EPerson;
import org.dspace.rest.common.Status;
import org.dspace.rest.common.User;
import org.dspace.rest.exceptions.ContextException;
/**
* Root of RESTful api. It provides login and logout. Also have method for
* printing every method which is provides by RESTful api.
*
* @author Rostislav Novak (Computing and Information Centre, CTU in Prague)
*
*/ */
@Path("/") @Path("/")
public class RestIndex { public class RestIndex {
private static Logger log = Logger.getLogger(RestIndex.class);
@javax.ws.rs.core.Context public static ServletContext servletContext; @javax.ws.rs.core.Context public static ServletContext servletContext;
/* /**
The "GET" annotation indicates this method will respond to HTTP Get requests. * Return html page with information about REST api. It contains methods all
The "Produces" annotation indicates the MIME response the method will return. * methods provide by REST api.
*
* @return HTML page which has information about all methods of REST api.
*/ */
@GET @GET
@Produces(MediaType.TEXT_HTML) @Produces(MediaType.TEXT_HTML)
public String sayHtmlHello() { public String sayHtmlHello() {
return "<html><title>DSpace REST</title>" + // TODO Better graphics, add arguments to all methods. (limit, offset, item and so on)
"<body><h1>DSpace REST API</h1>" + return "<html><title>DSpace REST - index</title>" +
"<ul>" + "<body>"
"<li><a href='" + servletContext.getContextPath() + "/communities'>/communities</a></li>" + + "<h1>DSpace REST API</h1>" +
"<li><a href='" + servletContext.getContextPath() + "/communities/1'>/communities/1</a></li>" + "Server path: " + servletContext.getContextPath() +
"<li><a href='" + servletContext.getContextPath() + "/collections'>/collections</a></li>" + "<h2>Index</h2>" +
"<li><a href='" + servletContext.getContextPath() + "/collections/1'>/collections/1</a></li>" + "<ul>" +
"<li><a href='" + servletContext.getContextPath() + "/items'>/items</a></li>" + "<li>GET / - It returns this page.</li>" +
"<li><a href='" + servletContext.getContextPath() + "/items/1'>/items/1</a></li>" + "<li>GET /test - Return string \"REST api is running\". It is method for testing.</li>" +
"<li><a href='" + servletContext.getContextPath() + "/bitstreams'>/bitstreams</a></li>" + "<li>POST /login - Method for login into DSpace RESTful api. You must post User class. Example: {\"email\":\"test@dspace\",\"password\":\"pass\"}. It returns token under which will must sending requests. In header \"rest-dspace-token\"</li>" +
"<li><a href='" + servletContext.getContextPath() + "/bitstreams/1'>/bitstreams/1</a></li>" + "<li>POST /logout - Method for logout from DSpace RESTful api. You must post request with header \"rest-dspace-token\" token</li>" +
"<li><a href='" + servletContext.getContextPath() + "/bitstreams/1/retrieve'>/bitstreams/1/retrieve</a></li>" + "</ul>" +
"</ul>" + "<h2>Communities</h2>" +
"<ul>" +
"<li>GET /communities - Returns array of all communities in DSpace.</li>" +
"<li>GET /communities/top-communities - Returns array of all top communities in DSpace.</li>" +
"<li>GET /communities/{communityId} - Returns community.</li>" +
"<li>GET /communities/{communityId}/collections - Returns array of collections of community.</li>" +
"<li>GET /communities/{communityId}/communities - Returns array of subcommunities of community.</li>" +
"<li>POST /communities - Create new community at top level. You must post community.</li>" +
"<li>POST /communities/{communityId}/collections - Create new collections in community. You must post collection.</li>" +
"<li>POST /communities/{communityId}/communities - Create new subcommunity in community. You must post community.</li>" +
"<li>PUT /communities/{communityId} - Update community.</li>" +
"<li>DELETE /communities/{communityId} - Delete community.</li>" +
"<li>DELETE /communities/{communityId}/collections/{collectionId} - Delete collection in community.</li>" +
"<li>DELETE /communities/{communityId}/communities/{communityId2} - Delete subcommunity in community.</li>" +
"</ul>" +
"<h2>Collections</h2>" +
"<ul>" +
"<li>GET /collections - Return all collections of DSpace in array.</li>" +
"<li>GET /collections/{collectionId} - Return collection with id.</li>" +
"<li>GET /collections/{collectionId}/items - Return all items of collection.</li>" +
"<li>POST /collections/{collectionId}/items - Create posted item in collection.</li>" +
"<li>POST /collections/find-collection - Find collection by passed name.</li>" +
"<li>PUT /collections/{collectionId} </li> - Update collection. You muset post collection." +
"<li>DELETE /collections/{collectionId} - Delete collection from DSpace.</li>" +
"<li>DELETE /collections/{collectionId}/items/{itemId} - Delete item in collection. </li>" +
"</ul>" +
"<h2>Items</h2>" +
"<ul>" +
"<li>GET /items - Return list of items.</li>" +
"<li>GET /items/{item id} - Return item.</li>" +
"<li>GET /items/{item id}/metadata - Return item metadata.</li>" +
"<li>GET /items/{item id}/bitstreams - Return item bitstreams.</li>" +
"<li>POST /items/find-by-metadata-field - Find items by metadata entry.</li>" +
"<li>POST /items/{item id}/metadata - Add metadata to item.</li>" +
"<li>POST /items/{item id}/bitstreams - Add bitstream to item.</li>" +
"<li>PUT /items/{item id}/metadata - Update metadata in item.</li>" +
"<li>DELETE /items/{item id} - Delete item.</li>" +
"<li>DELETE /items/{item id}/metadata - Clear item metadata.</li>" +
"<li>DELETE /items/{item id}/bitstreams/{bitstream id} - Delete item bitstream.</li>" +
"</ul>" +
"<h2>Bitstreams</h2>" +
"<ul>" +
"<li>GET /bitstreams - Return all bitstreams in DSpace.</li>" +
"<li>GET /bitstreams/{bitstream id} - Return bitstream.</li>" +
"<li>GET /bitstreams/{bitstream id}/policy - Return bitstream policies.</li>" +
"<li>POST /bitstreams/{bitstream id}/retrieve - Return data of bitstream.</li>" +
"<li>POST /bitstreams/{bitstream id}/policy - Add policy to item.</li>" +
"<li>PUT /bitstreams/{bitstream id}/data - Update data of bitstream.</li>" +
"<li>PUT /bitstreams/{bitstream id} - Update metadata of bitstream.</li>" +
"<li>DELETE /bitstreams/{bitstream id} - Delete bitstream from DSpace.</li>" +
"<li>DELETE /bitstreams/{bitstream id}/policy/{policy_id} - Delete bitstream policy.</li>" +
"</ul>" +
"</body></html> "; "</body></html> ";
} }
/**
* Method for only test if rest api is running.
*
* @return String "REST api is running."
*/
@GET
@Path("/test")
public String test()
{
return "REST api is running.";
}
/**
* Method for login user into REST api.
*
* @param user
* User which will be logged into REST api.
* @return Returns response code OK with token. Otherwise returns response
* code FORBIDDEN(403).
*/
@POST
@Path("/login")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response login(User user)
{
String token = TokenHolder.login(user);
if (token == null)
{
log.info("REST Login Attempt failed for user: " + user.getEmail());
return Response.status(Response.Status.FORBIDDEN).build();
} else {
log.info("REST Login Success for user: " + user.getEmail());
return Response.ok(token, "text/plain").build();
}
}
/**
* Method for logout from DSpace REST api. It removes token and user from
* TokenHolder.
*
* @param headers
* Request header which contains header with key
* "rest-dspace-token" and value of token.
* @return Return response OK, otherwise BAD_REQUEST, if was problem with
* logout or token is incorrect.
*/
@POST
@Path("/logout")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response logout(@Context HttpHeaders headers)
{
List<String> list = headers.getRequestHeader(TokenHolder.TOKEN_HEADER);
String token = null;
boolean logout = false;
EPerson ePerson = null;
if (list != null)
{
token = list.get(0);
ePerson = TokenHolder.getEPerson(token);
logout = TokenHolder.logout(token);
}
if ((token == null) || (!logout))
{
return Response.status(Response.Status.BAD_REQUEST).build();
}
if(ePerson != null) {
log.info("REST Logout: " + ePerson.getEmail());
}
return Response.ok().build();
}
/**
* ? status: OK
* authenticated: TRUE | FALSE
* epersonEMAIL: user@dspace.org
* epersonNAME: Joe User
* @param headers
* @return
*/
@GET
@Path("/status")
@Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Status status(@Context HttpHeaders headers) throws UnsupportedEncodingException {
org.dspace.core.Context context = null;
try {
context = Resource.createContext(Resource.getUser(headers));
EPerson ePerson = context.getCurrentUser();
if(ePerson != null) {
//DB EPerson needed since token won't have full info, need context
EPerson dbEPerson = EPerson.findByEmail(context, ePerson.getEmail());
String token = Resource.getToken(headers);
Status status = new Status(dbEPerson.getEmail(), dbEPerson.getFullName(), token);
return status;
}
} catch (ContextException e)
{
Resource.processException("Status context error: " + e.getMessage(), context);
} catch (SQLException e) {
Resource.processException("Status eperson db lookup error: " + e.getMessage(), context);
} catch (AuthorizeException e) {
Resource.processException("Status eperson authorize exception: " + e.getMessage(), context);
} finally {
context.abort();
}
//fallback status, unauth
return new Status();
}
} }

View File

@@ -0,0 +1,154 @@
/**
* 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 java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import org.apache.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.eperson.EPerson;
import org.dspace.rest.common.User;
/**
* This class provide token generation, token holding and logging user into rest
* api. For login use method login with class org.dspace.rest.common.User. If
* you want to be deleted from holder, use method for logout.
*
* @author Rostislav Novak (Computing and Information Centre, CTU in Prague)
*/
public class TokenHolder
{
private static final Logger log = Logger.getLogger(TokenHolder.class);
public static String TOKEN_HEADER = "rest-dspace-token";
private static Map<String, String> tokens = new HashMap<String, String>(); // Map with pair Email,token
private static Map<String, EPerson> persons = new HashMap<String, EPerson>(); // Map with pair token,Eperson
/**
* Login user into rest api. It check user credentials if they are okay.
*
* @param user
* User which will be logged into rest api.
* @return Returns generated token, which must be used in request header
* under rest-api-token. If password is bad or user does not exist,
* it returns NULL.
* @throws WebApplicationException
* It is thrown by SQLException if user could not be read from
* database. And by Authorization exception if context has not
* permission to read eperson.
*/
public static String login(User user) throws WebApplicationException
{
org.dspace.core.Context context = null;
String token = null;
try
{
context = new org.dspace.core.Context();
EPerson dspaceUser = EPerson.findByEmail(context, user.getEmail());
if ((dspaceUser == null) || (!dspaceUser.checkPassword(user.getPassword())))
{
token = null;
}
else if (tokens.containsKey(user.getEmail()))
{
token = tokens.get(user.getEmail());
}
else
{
token = generateToken();
persons.put(token, dspaceUser);
tokens.put(user.getEmail(), token);
}
log.trace("User(" + user.getEmail() + ") has been logged.");
context.complete();
}
catch (SQLException e)
{
context.abort();
log.error("Could not read user from database. Message:" + e);
throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
}
catch (AuthorizeException e)
{
context.abort();
log.error("Could not find user, AuthorizeException. Message:" + e);
throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
}
finally
{
if ((context != null) && (context.isValid()))
{
context.abort();
log.error("Something get wrong. Aborting context in finally statement.");
throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
}
}
return token;
}
/**
* Return EPerson for log into context.
*
* @param token
* Token under which is stored eperson.
* @return Return instance of EPerson if is token right, otherwise it
* returns NULL.
*/
public static EPerson getEPerson(String token)
{
return persons.get(token);
}
/**
* Logout user from rest api. It delete token and EPerson from TokenHolder.
*
* @param token
* Token under which is stored eperson.
* @return Return true if was all okay, otherwise return false.
*/
public static boolean logout(String token)
{
if ((token == null) || (persons.get(token) == null))
{
return false;
}
String email = persons.get(token).getEmail();
EPerson person = persons.remove(token);
if (person == null)
{
return false;
}
tokens.remove(email);
return true;
}
/**
* It generates unique token.
*
* @return String filled with unique token.
*/
private static String generateToken()
{
return UUID.randomUUID().toString();
}
}

View File

@@ -7,15 +7,17 @@
*/ */
package org.dspace.rest.common; 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.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
import org.apache.log4j.Logger;
import org.dspace.content.Bundle;
import org.dspace.core.Constants;
/** /**
* Created with IntelliJ IDEA. * Created with IntelliJ IDEA.
* User: peterdietz * User: peterdietz
@@ -36,7 +38,9 @@ public class Bitstream extends DSpaceObject {
private String retrieveLink; private String retrieveLink;
private CheckSum checkSum; private CheckSum checkSum;
private Integer sequenceId; private Integer sequenceId;
private ResourcePolicy[] policies = null;
public Bitstream() { public Bitstream() {
} }
@@ -72,8 +76,22 @@ public class Bitstream extends DSpaceObject {
if(expandFields.contains("parent") || expandFields.contains("all")) { if(expandFields.contains("parent") || expandFields.contains("all")) {
parentObject = new DSpaceObject(bitstream.getParentObject()); parentObject = new DSpaceObject(bitstream.getParentObject());
} else if(expandFields.contains("policies") || expandFields.contains("all")) {
List<ResourcePolicy> tempPolicies = new ArrayList<ResourcePolicy>();
Bundle[] bundles = bitstream.getBundles();
for (Bundle bundle : bundles) {
List<org.dspace.authorize.ResourcePolicy> bitstreamsPolicies = bundle.getBitstreamPolicies();
for (org.dspace.authorize.ResourcePolicy policy : bitstreamsPolicies) {
if (policy.getResourceID() == this.getId()) {
tempPolicies.add(new ResourcePolicy(policy));
}
}
}
policies = tempPolicies.toArray(new ResourcePolicy[0]);
} else { } else {
this.addExpand("parent"); this.addExpand("parent");
this.addExpand("policies");
} }
if(!expandFields.contains("all")) { if(!expandFields.contains("all")) {
@@ -153,4 +171,13 @@ public class Bitstream extends DSpaceObject {
this.checkSum = checkSum; this.checkSum = checkSum;
} }
public ResourcePolicy[] getPolicies() {
return policies;
}
public void setPolicies(ResourcePolicy[] policies) {
this.policies = policies;
}
} }

View File

@@ -13,7 +13,6 @@ import org.dspace.content.ItemIterator;
import org.dspace.core.Context; import org.dspace.core.Context;
import javax.ws.rs.WebApplicationException; import javax.ws.rs.WebApplicationException;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlRootElement;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;

View File

@@ -38,8 +38,9 @@ public class Community extends DSpaceObject{
private String copyrightText, introductoryText, shortDescription, sidebarText; private String copyrightText, introductoryText, shortDescription, sidebarText;
private Integer countItems; private Integer countItems;
// Renamed because of xml annotation exception with this attribute and getSubCommunities.
@XmlElement(name = "subcommunities", required = true) @XmlElement(name = "subcommunities", required = true)
private List<Community> subCommunities = new ArrayList<Community>(); private List<Community> subcommunities = new ArrayList<Community>();
private List<Collection> collections = new ArrayList<Collection>(); private List<Collection> collections = new ArrayList<Collection>();
@@ -87,10 +88,10 @@ public class Community extends DSpaceObject{
if(expandFields.contains("subCommunities") || expandFields.contains("all")) { if(expandFields.contains("subCommunities") || expandFields.contains("all")) {
org.dspace.content.Community[] communityArray = community.getSubcommunities(); org.dspace.content.Community[] communityArray = community.getSubcommunities();
subCommunities = new ArrayList<Community>(); subcommunities = new ArrayList<Community>();
for(org.dspace.content.Community subCommunity : communityArray) { for(org.dspace.content.Community subCommunity : communityArray) {
if(AuthorizeManager.authorizeActionBoolean(context, subCommunity, org.dspace.core.Constants.READ)) { if(AuthorizeManager.authorizeActionBoolean(context, subCommunity, org.dspace.core.Constants.READ)) {
subCommunities.add(new Community(subCommunity, null, context)); subcommunities.add(new Community(subCommunity, null, context));
} else { } else {
log.info("Omitted restricted subCommunity: " + subCommunity.getID() + " _ " + subCommunity.getName()); log.info("Omitted restricted subCommunity: " + subCommunity.getID() + " _ " + subCommunity.getName());
} }
@@ -171,4 +172,13 @@ public class Community extends DSpaceObject{
public Bitstream getLogo() { public Bitstream getLogo() {
return logo; return logo;
} }
public List<Community> getSubcommunities() {
return subcommunities;
}
public void setSubcommunities(List<Community> subcommunities) {
this.subcommunities = subcommunities;
}
} }

View File

@@ -11,6 +11,7 @@ import org.atteo.evo.inflector.English;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlRootElement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -26,9 +27,7 @@ public class DSpaceObject {
private Integer id; private Integer id;
private String name; private String name;
private String handle; private String handle;
private String type; private String type;
@XmlElement(name = "link", required = true) @XmlElement(name = "link", required = true)
@@ -42,17 +41,17 @@ public class DSpaceObject {
} }
public DSpaceObject(org.dspace.content.DSpaceObject dso) { public DSpaceObject(org.dspace.content.DSpaceObject dso) {
setID(dso.getID()); setId(dso.getID());
setName(dso.getName()); setName(dso.getName());
setHandle(dso.getHandle()); setHandle(dso.getHandle());
setType(dso.getTypeText().toLowerCase()); setType(dso.getTypeText().toLowerCase());
} }
public Integer getID() { public Integer getId() {
return id; return id;
} }
public void setID(Integer id) { public void setId(Integer id) {
this.id = id; this.id = id;
} }
@@ -74,7 +73,7 @@ public class DSpaceObject {
public String getLink() { public String getLink() {
//TODO, get actual contextPath of /rest/ //TODO, get actual contextPath of /rest/
return "/rest/" + English.plural(getType()) + "/" + getID(); return "/RESTapi/" + English.plural(getType()) + "/" + getId();
} }
public String getType() { public String getType() {

View File

@@ -17,6 +17,7 @@ import org.dspace.core.Context;
import javax.ws.rs.WebApplicationException; import javax.ws.rs.WebApplicationException;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlRootElement;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -29,6 +30,7 @@ import java.util.List;
* Time: 4:50 PM * Time: 4:50 PM
* To change this template use File | Settings | File Templates. * To change this template use File | Settings | File Templates.
*/ */
@SuppressWarnings("deprecation")
@XmlRootElement(name = "item") @XmlRootElement(name = "item")
public class Item extends DSpaceObject { public class Item extends DSpaceObject {
Logger log = Logger.getLogger(Item.class); Logger log = Logger.getLogger(Item.class);
@@ -39,11 +41,8 @@ public class Item extends DSpaceObject {
Collection parentCollection; Collection parentCollection;
List<Collection> parentCollectionList; List<Collection> parentCollectionList;
List<Community> parentCommunityList; List<Community> parentCommunityList;
List<MetadataEntry> metadata; List<MetadataEntry> metadata;
List<Bitstream> bitstreams; List<Bitstream> bitstreams;
public Item(){} public Item(){}
@@ -63,9 +62,8 @@ public class Item extends DSpaceObject {
metadata = new ArrayList<MetadataEntry>(); 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); 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) { for (DCValue dcv : dcvs) {
if (!MetadataExposure.isHidden(context, dcv.schema, dcv.element, dcv.qualifier)) { if (!MetadataExposure.isHidden(context, dcv.schema, dcv.element, dcv.qualifier))
metadata.add(new MetadataEntry(dcv.getField(), dcv.value)); metadata.add(new MetadataEntry(dcv.getField(), dcv.value, dcv.language));
}
} }
} else { } else {
this.addExpand("metadata"); this.addExpand("metadata");

View File

@@ -10,37 +10,58 @@ package org.dspace.rest.common;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlRootElement;
/** /**
* Created with IntelliJ IDEA. * @author peterdietz, Rostislav Novak (Computing and Information Centre, CTU in
* User: peterdietz * Prague)
* Date: 9/20/13 *
* Time: 5:51 PM
* To change this template use File | Settings | File Templates.
*/ */
@XmlRootElement(name = "metadataentry") @XmlRootElement(name = "metadataentry")
public class MetadataEntry { public class MetadataEntry
{
String key; String key;
String value; String value;
public MetadataEntry() {} String language;
public MetadataEntry(String key, String value) { public MetadataEntry()
this.key = key; {
this.value = value;
} }
public String getValue() { public MetadataEntry(String key, String value, String language)
{
this.key = key;
this.value = value;
this.language = language;
}
public String getValue()
{
return value; return value;
} }
public void setValue(String value) { public void setValue(String value)
{
this.value = value; this.value = value;
} }
public String getKey() { public String getKey()
{
return key; return key;
} }
public void setKey(String key) { public void setKey(String key)
{
this.key = key; this.key = key;
} }
public String getLanguage()
{
return language;
}
public void setLanguage(String language)
{
this.language = language;
}
} }

View File

@@ -0,0 +1,181 @@
/**
* 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 java.util.Date;
import org.codehaus.jackson.annotate.JsonIgnore;
public class ResourcePolicy{
public enum Action {
READ, WRITE, DELETE;
}
private Integer id;
private Action action;
private Integer epersonId;
private Integer groupId;
private Integer resourceId;
private String resourceType;
private String rpDescription;
private String rpName;
private String rpType;
private Date startDate;
private Date endDate;
public ResourcePolicy() {}
public ResourcePolicy(org.dspace.authorize.ResourcePolicy dspacePolicy) {
this.id = dspacePolicy.getID();
switch(dspacePolicy.getAction()) {
case org.dspace.core.Constants.READ:
this.action = Action.READ;
break;
case org.dspace.core.Constants.WRITE:
this.action = Action.WRITE;
break;
case org.dspace.core.Constants.DELETE:
this.action = Action.DELETE;
break;
}
this.epersonId = dspacePolicy.getEPersonID();
this.groupId = dspacePolicy.getGroupID();
this.resourceId = dspacePolicy.getResourceID();
this.rpDescription = dspacePolicy.getRpDescription();
this.rpName = dspacePolicy.getRpName();
this.rpType = dspacePolicy.getRpType();
this.startDate = dspacePolicy.getStartDate();
this.endDate = dspacePolicy.getEndDate();
switch(dspacePolicy.getResourceType()) {
case org.dspace.core.Constants.BITSTREAM:
this.resourceType = "bitstream";
break;
case org.dspace.core.Constants.ITEM:
this.resourceType = "item";
break;
case org.dspace.core.Constants.COLLECTION:
this.resourceType = "collection";
break;
case org.dspace.core.Constants.COMMUNITY:
this.resourceType = "community";
break;
case org.dspace.core.Constants.BUNDLE:
this.resourceType = "bundle";
break;
default:
this.resourceType = "";
break;
}
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Action getAction() {
return action;
}
@JsonIgnore
public int getActionInt(){
switch(action) {
case READ:
return org.dspace.core.Constants.READ;
case WRITE:
return org.dspace.core.Constants.WRITE;
case DELETE:
return org.dspace.core.Constants.DELETE;
}
return org.dspace.core.Constants.READ;
}
public void setAction(Action action) {
this.action = action;
}
public Integer getEpersonId() {
return epersonId;
}
public void setEpersonId(Integer epersonId) {
this.epersonId = epersonId;
}
public Integer getGroupId() {
return groupId;
}
public void setGroupId(Integer groupId) {
this.groupId = groupId;
}
public Integer getResourceId() {
return resourceId;
}
public void setResourceId(Integer resourceId) {
this.resourceId = resourceId;
}
public String getResourceType() {
return resourceType;
}
public void setResourceType(String resourceType) {
this.resourceType = resourceType;
}
public String getRpDescription() {
return rpDescription;
}
public void setRpDescription(String rpDescription) {
this.rpDescription = rpDescription;
}
public String getRpName() {
return rpName;
}
public void setRpName(String rpName) {
this.rpName = rpName;
}
public String getRpType() {
return rpType;
}
public void setRpType(String rpType) {
this.rpType = rpType;
}
public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public Date getEndDate() {
return endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
}

View File

@@ -0,0 +1,105 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.rest.common;
import org.codehaus.jackson.annotate.JsonProperty;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Used to handle/determine status of REST API.
* Mainly to know your authentication status
*
*/
@XmlRootElement(name = "status")
public class Status
{
private boolean okay;
private boolean authenticated;
private String email;
private String fullname;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
private String token;
public Status() {
setOkay(true);
setAuthenticated(false);
}
public Status(String email, String fullname, String token) {
setOkay(true);
setAuthenticated(true);
setEmail(email);
setFullname(fullname);
setToken(token);
}
public Status(EPerson eperson, String token) {
setOkay(true);
if(eperson != null) {
setAuthenticated(true);
setEmail(eperson.getEmail());
setFullname(eperson.getFullName());
setToken(token);
} else {
setAuthenticated(false);
}
}
@JsonProperty("okay")
public boolean isOkay()
{
return this.okay;
}
@JsonProperty("okay")
public void setOkay(boolean okay)
{
this.okay = okay;
}
@JsonProperty("authenticated")
public boolean isAuthenticated() {
return authenticated;
}
@JsonProperty("authenticated")
public void setAuthenticated(boolean authenticated) {
this.authenticated = authenticated;
}
@JsonProperty("email")
public String getEmail() {
return email;
}
@JsonProperty("email")
public void setEmail(String email) {
this.email = email;
}
@JsonProperty("fullname")
public String getFullname() {
return fullname;
}
@JsonProperty("fullname")
public void setFullname(String fullname) {
this.fullname = fullname;
}
}

View File

@@ -0,0 +1,56 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.rest.common;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Class for handle login information for POST request.
*
* @author Rostislav Novak (Computing and Information Centre, CTU in Prague)
*
*/
@XmlRootElement(name = "user")
public class User
{
private String email;
private String password;
public User()
{
}
public User(String email, String password)
{
this.email = email;
this.password = password;
}
public String getEmail()
{
return email;
}
public void setEmail(String email)
{
this.email = email;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
}

View File

@@ -0,0 +1,35 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.rest.exceptions;
/**
* Simple exception which only encapsulate classic exception. This exception is
* only for exceptions caused by creating context.
*
* @author Rostislav Novak (Computing and Information Centre, CTU in Prague)
*
*/
public class ContextException extends Exception
{
private static final long serialVersionUID = 1L;
Exception causedBy;
public ContextException(String message, Exception causedBy)
{
super(message);
this.causedBy = causedBy;
}
public Exception getCausedBy()
{
return causedBy;
}
}

View File

@@ -36,23 +36,23 @@
--> -->
<load-on-startup>1</load-on-startup> <load-on-startup>1</load-on-startup>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>DSpace REST API</servlet-name> <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> <url-pattern>/*</url-pattern>
</servlet-mapping> </servlet-mapping>
<!-- Security settings and mapping -->
<security-constraint>
<web-resource-collection>
<web-resource-name>DSpace REST API</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<!-- DSpace Configuration Information --> <!-- DSpace Configuration Information -->
<context-param> <context-param>
<param-name>dspace-config</param-name> <param-name>dspace-config</param-name>
@@ -84,20 +84,18 @@
</listener> </listener>
<!-- kernel start listener (from impl) <!-- kernel start listener (from impl)
The following listener can be used instead of the filter below, it is simpler, cleaner 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 and eliminates the need for a DSpaceKernelServletFilter filter to be involved with the
request cycle. request cycle.
--> -->
<listener> <listener>
<listener-class>org.dspace.servicemanager.servlet.DSpaceKernelServletContextListener</listener-class> <listener-class>org.dspace.servicemanager.servlet.DSpaceKernelServletContextListener</listener-class>
</listener> </listener>
<listener> <listener>
<listener-class> <listener-class>
org.springframework.web.context.ContextLoaderListener org.springframework.web.context.ContextLoaderListener
</listener-class> </listener-class>
</listener> </listener>
</web-app>
</web-app>