mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 01:54:22 +00:00
[DS-1005] SWORD v2 implementation for DSpace : Restructure project and use external SWORD dependency.
git-svn-id: http://scm.dspace.org/svn/repo/dspace/trunk@6678 9c30dcfa-912a-0410-8fc2-9e0234be79fd
This commit is contained in:
@@ -1,102 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<name>DSpace SWORD v2 :: API and Implementation</name>
|
||||
<description>DSpace SWORD v2 Deposit Service Provider Web Application</description>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-swordv2-api</artifactId>
|
||||
<version>1.8.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<!--
|
||||
A Parent POM that Maven inherits DSpace Default
|
||||
POM atrributes from.
|
||||
-->
|
||||
<parent>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-swordv2</artifactId>
|
||||
<version>1.8.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
<scm>
|
||||
<connection>scm:svn:http://scm.dspace.org/svn/repo/dspace/trunk/dspace-swordv2/dspace-swordv2-api</connection>
|
||||
<developerConnection>scm:svn:https://scm.dspace.org/svn/repo/dspace/trunk/dspace-swordv2/dspace-swordv2-api</developerConnection>
|
||||
<url>http://scm.dspace.org/svn/repo/dspace/trunk/dspace-swordv2/dspace-swordv2-api</url>
|
||||
</scm>
|
||||
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-api</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-services-impl</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-api-lang</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.15</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>javax.mail</groupId>
|
||||
<artifactId>mail</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>javax.jms</groupId>
|
||||
<artifactId>jms</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.sun.jdmk</groupId>
|
||||
<artifactId>jmxtools</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.sun.jmx</groupId>
|
||||
<artifactId>jmxri</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.abdera</groupId>
|
||||
<artifactId>abdera-client</artifactId>
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-fileupload</groupId>
|
||||
<artifactId>commons-fileupload</artifactId>
|
||||
<version>1.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hp.hpl.jena</groupId>
|
||||
<artifactId>jena</artifactId>
|
||||
<version>2.6.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>xom</groupId>
|
||||
<artifactId>xom</artifactId>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@@ -1,131 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import org.apache.abdera.Abdera;
|
||||
import org.apache.abdera.i18n.iri.IRI;
|
||||
import org.apache.abdera.model.Category;
|
||||
import org.apache.abdera.model.Element;
|
||||
import org.apache.abdera.model.Entry;
|
||||
import org.apache.abdera.model.Feed;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class AtomStatement extends Statement
|
||||
{
|
||||
private String author;
|
||||
private String feedUri;
|
||||
private String title;
|
||||
private String updated;
|
||||
|
||||
public AtomStatement(String feedUri, String author, String title, String updated)
|
||||
{
|
||||
this.contentType = "application/atom+xml;type=feed";
|
||||
this.author = author != null ? author : "Unknown";
|
||||
this.feedUri = feedUri;
|
||||
this.title = title != null ? title : "Untitled";
|
||||
this.updated = updated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(Writer out)
|
||||
throws IOException
|
||||
{
|
||||
Abdera abdera = new Abdera();
|
||||
Feed feed = abdera.newFeed();
|
||||
|
||||
// id
|
||||
// link@rel="self" -> point to id
|
||||
// title
|
||||
// updated
|
||||
feed.setId(this.feedUri);
|
||||
feed.addLink(this.feedUri, "self");
|
||||
feed.setTitle(this.title);
|
||||
feed.addAuthor(this.author);
|
||||
|
||||
if (this.updated != null)
|
||||
{
|
||||
feed.setUpdated(this.updated);
|
||||
}
|
||||
else
|
||||
{
|
||||
feed.setUpdated(new Date());
|
||||
}
|
||||
|
||||
// create an entry for each Resource Part
|
||||
for (ResourcePart resource : this.resources)
|
||||
{
|
||||
Entry entry = feed.addEntry();
|
||||
|
||||
// id
|
||||
// summary
|
||||
// title
|
||||
// updated
|
||||
entry.setContent(new IRI(resource.getUri()), resource.getMediaType());
|
||||
entry.setId(resource.getUri());
|
||||
entry.setTitle("Resource " + resource.getUri());
|
||||
entry.setSummary("Resource Part");
|
||||
entry.setUpdated(new Date());
|
||||
}
|
||||
|
||||
// create an entry for each original deposit
|
||||
for (OriginalDeposit deposit : this.originalDeposits)
|
||||
{
|
||||
Entry entry = feed.addEntry();
|
||||
|
||||
// id
|
||||
// summary
|
||||
// title
|
||||
// updated
|
||||
entry.setId(deposit.getUri());
|
||||
entry.setTitle("Original Deposit " + deposit.getUri());
|
||||
entry.setSummary("Original Deposit");
|
||||
entry.setUpdated(new Date());
|
||||
|
||||
entry.setContent(new IRI(deposit.getUri()), deposit.getMediaType());
|
||||
entry.addCategory(UriRegistry.SWORD_TERMS_NAMESPACE, UriRegistry.SWORD_ORIGINAL_DEPOSIT, "Original Deposit");
|
||||
if (deposit.getDepositedOn() != null)
|
||||
{
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||
entry.addSimpleExtension(new QName(UriRegistry.SWORD_DEPOSITED_ON), sdf.format(deposit.getDepositedOn()));
|
||||
}
|
||||
|
||||
if (deposit.getDepositedOnBehalfOf() != null)
|
||||
{
|
||||
entry.addSimpleExtension(new QName(UriRegistry.SWORD_DEPOSITED_ON_BEHALF_OF), deposit.getDepositedOnBehalfOf());
|
||||
}
|
||||
|
||||
if (deposit.getDepositedBy() != null)
|
||||
{
|
||||
entry.addSimpleExtension(new QName(UriRegistry.SWORD_DEPOSITED_BY), deposit.getDepositedBy());
|
||||
}
|
||||
|
||||
for (String packaging : deposit.getPackaging())
|
||||
{
|
||||
entry.addSimpleExtension(UriRegistry.SWORD_PACKAGING, packaging);
|
||||
}
|
||||
}
|
||||
|
||||
// now at the state as a categories
|
||||
for (String state : this.states.keySet())
|
||||
{
|
||||
Category cat = feed.addCategory(UriRegistry.SWORD_STATE, state, "State");
|
||||
if (this.states.get(state) != null)
|
||||
{
|
||||
cat.setText(this.states.get(state));
|
||||
}
|
||||
}
|
||||
|
||||
// now write the feed
|
||||
feed.writeTo(out);
|
||||
}
|
||||
}
|
@@ -1,37 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
public class AuthCredentials
|
||||
{
|
||||
private String username;
|
||||
private String password;
|
||||
private String onBehalfOf;
|
||||
|
||||
public AuthCredentials(String username, String password, String onBehalfOf)
|
||||
{
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.onBehalfOf = onBehalfOf;
|
||||
}
|
||||
|
||||
public String getUsername()
|
||||
{
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getPassword()
|
||||
{
|
||||
return password;
|
||||
}
|
||||
|
||||
public String getOnBehalfOf()
|
||||
{
|
||||
return onBehalfOf;
|
||||
}
|
||||
}
|
@@ -1,165 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Utility class that holds Checksum related methods.
|
||||
*
|
||||
* @author Neil Taylor, Stuart Lewis
|
||||
*/
|
||||
public class ChecksumUtils
|
||||
{
|
||||
/** Logger */
|
||||
private static Logger log = Logger.getLogger(ChecksumUtils.class);
|
||||
|
||||
/**
|
||||
* Generate an MD5 hash for the file that is specified in the
|
||||
* filepath. The hash is returned as a String representation.
|
||||
*
|
||||
* @param filepath The path to the file to load.
|
||||
* @return A string hash of the file.
|
||||
* @throws NoSuchAlgorithmException If the MD5 algorithm is
|
||||
* not supported by the installed virtual machine.
|
||||
*
|
||||
* @throws IOException If there is an error accessing the file.
|
||||
*/
|
||||
public static String generateMD5(String filepath)
|
||||
throws NoSuchAlgorithmException, IOException
|
||||
{
|
||||
return generateMD5(new FileInputStream(filepath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an MD5 hash for the file that is specified in the
|
||||
* filepath. The hash is returned as a String representation.
|
||||
*
|
||||
* @param md5Stream The InputStream to checksum.
|
||||
* @return A string hash of the file.
|
||||
* @throws NoSuchAlgorithmException If the MD5 algorithm is
|
||||
* not supported by the installed virtual machine.
|
||||
*
|
||||
* @throws IOException If there is an error accessing the file.
|
||||
*/
|
||||
public static String generateMD5(InputStream md5Stream)
|
||||
throws NoSuchAlgorithmException, IOException
|
||||
{
|
||||
String md5 = null;
|
||||
|
||||
try
|
||||
{
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
md.reset();
|
||||
|
||||
byte[] bytes = new byte[1024];
|
||||
int count = 0;
|
||||
while( (count = md5Stream.read(bytes)) != -1 )
|
||||
{
|
||||
md.update(bytes, 0, count);
|
||||
}
|
||||
|
||||
byte[] md5Digest = md.digest();
|
||||
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for( byte b : md5Digest )
|
||||
{
|
||||
// 0xFF is used to handle the issue of negative numbers in the bytes
|
||||
String hex = Integer.toHexString(b & 0xFF);
|
||||
if( hex.length() == 1 )
|
||||
{
|
||||
buffer.append("0");
|
||||
}
|
||||
buffer.append(hex);
|
||||
}
|
||||
|
||||
md5 = buffer.toString();
|
||||
}
|
||||
catch(NoSuchAlgorithmException ex )
|
||||
{
|
||||
log.error("MD5 Algorithm Not found");
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if( md5Stream != null )
|
||||
{
|
||||
md5Stream.close();
|
||||
}
|
||||
}
|
||||
|
||||
return md5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an MD5 hash for the file that is specified in the
|
||||
* filepath. The hash is returned as a String representation.
|
||||
*
|
||||
* @param bytes The byte array to checksum.
|
||||
* @return A string hash of the file.
|
||||
* @throws NoSuchAlgorithmException If the MD5 algorithm is
|
||||
* not supported by the installed virtual machine.
|
||||
*
|
||||
* @throws IOException If there is an error accessing the file.
|
||||
*/
|
||||
public static String generateMD5(byte[] bytes)
|
||||
throws NoSuchAlgorithmException, IOException
|
||||
{
|
||||
String md5 = null;
|
||||
|
||||
try
|
||||
{
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
md.reset();
|
||||
|
||||
md.update(bytes);
|
||||
|
||||
|
||||
byte[] md5Digest = md.digest();
|
||||
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for( byte b : md5Digest )
|
||||
{
|
||||
// 0xFF is used to handle the issue of negative numbers in the bytes
|
||||
String hex = Integer.toHexString(b & 0xFF);
|
||||
if( hex.length() == 1 )
|
||||
{
|
||||
buffer.append("0");
|
||||
}
|
||||
buffer.append(hex);
|
||||
}
|
||||
|
||||
md5 = buffer.toString();
|
||||
}
|
||||
catch(NoSuchAlgorithmException ex )
|
||||
{
|
||||
log.error("MD5 Algorithm Not found");
|
||||
throw ex; // rethrow
|
||||
}
|
||||
|
||||
return md5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a simple test to process the file.
|
||||
*
|
||||
* @param args The command line arguments.
|
||||
* @throws NoSuchAlgorithmException If there was an error generating the MD5.
|
||||
* @throws IOException If there is an error accessing the file.
|
||||
*/
|
||||
public static void main(String[] args)
|
||||
throws NoSuchAlgorithmException, IOException
|
||||
{
|
||||
System.out.println(ChecksumUtils.generateMD5(args[0]));
|
||||
}
|
||||
}
|
@@ -1,242 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import org.apache.abdera.i18n.iri.IRI;
|
||||
import org.apache.abdera.model.Element;
|
||||
import org.apache.abdera.model.Entry;
|
||||
import org.apache.abdera.model.Feed;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class CollectionAPI extends SwordAPIEndpoint
|
||||
{
|
||||
private static Logger log = Logger.getLogger(CollectionAPI.class);
|
||||
|
||||
protected CollectionListManager clm = null;
|
||||
protected CollectionDepositManager cdm;
|
||||
|
||||
public CollectionAPI(CollectionListManager clm, CollectionDepositManager cdm, SwordConfiguration config)
|
||||
{
|
||||
super(config);
|
||||
this.clm = clm;
|
||||
this.cdm = cdm;
|
||||
}
|
||||
|
||||
public void get(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
// first find out if this is supported
|
||||
if (this.clm == null)
|
||||
{
|
||||
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
|
||||
return;
|
||||
}
|
||||
|
||||
// do the initial authentication
|
||||
AuthCredentials auth = null;
|
||||
try
|
||||
{
|
||||
auth = this.getAuthCredentials(req);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
if (e.isRetry())
|
||||
{
|
||||
String s = "Basic realm=\"SWORD2\"";
|
||||
resp.setHeader("WWW-Authenticate", s);
|
||||
resp.setStatus(401);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Feed feed = this.clm.listCollectionContents(new IRI(this.getFullUrl(req)), auth, this.config);
|
||||
|
||||
// since the spec doesn't require the collection to be listable, this might
|
||||
// give us back null
|
||||
if (feed == null)
|
||||
{
|
||||
// method not allowed
|
||||
resp.sendError(405, "This server does not support listing collection contents");
|
||||
return;
|
||||
}
|
||||
|
||||
// otherwise process and return
|
||||
this.addGenerator(feed, this.config);
|
||||
|
||||
resp.setHeader("Content-Type", "application/atom+xml;type=feed");
|
||||
feed.writeTo(resp.getWriter());
|
||||
resp.getWriter().flush();
|
||||
}
|
||||
catch (SwordServerException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
// authentication actually failed at the server end; not a SwordError, but
|
||||
// need to throw a 403 Forbidden
|
||||
resp.sendError(403);
|
||||
}
|
||||
catch (SwordError se)
|
||||
{
|
||||
this.swordError(req, resp, se);
|
||||
}
|
||||
}
|
||||
|
||||
public void post(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
// do the initial authentication
|
||||
AuthCredentials auth = null;
|
||||
try
|
||||
{
|
||||
auth = this.getAuthCredentials(req);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
if (e.isRetry())
|
||||
{
|
||||
String s = "Basic realm=\"SWORD2\"";
|
||||
resp.setHeader("WWW-Authenticate", s);
|
||||
resp.setStatus(401);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// the first thing to do is determine what the deposit type is:
|
||||
String contentType = this.getContentType(req);
|
||||
boolean isMultipart = contentType.startsWith("multipart/related");
|
||||
boolean isEntryOnly = contentType.startsWith("application/atom+xml");
|
||||
boolean isBinaryOnly = !isMultipart && !isEntryOnly;
|
||||
|
||||
// get the common HTTP headers before leaping into the deposit type specific processes
|
||||
String slug = req.getHeader("Slug");
|
||||
boolean inProgress = this.getInProgress(req);
|
||||
|
||||
Deposit deposit = new Deposit();
|
||||
deposit.setInProgress(inProgress);
|
||||
deposit.setSlug(slug);
|
||||
DepositReceipt receipt = null;
|
||||
|
||||
// do the different kinds of deposit details extraction
|
||||
if (isMultipart)
|
||||
{
|
||||
this.addDepositPropertiesFromMultipart(deposit, req);
|
||||
}
|
||||
else if (isEntryOnly)
|
||||
{
|
||||
this.addDepositPropertiesFromEntry(deposit, req);
|
||||
}
|
||||
else if (isBinaryOnly)
|
||||
{
|
||||
this.addDepositPropertiesFromBinary(deposit, req);
|
||||
}
|
||||
|
||||
// now send the deposit to the implementation for processing
|
||||
String colUri = this.getFullUrl(req);
|
||||
receipt = this.cdm.createNew(colUri, deposit, auth, this.config);
|
||||
this.addGenerator(receipt, this.config);
|
||||
|
||||
// prepare and return the response
|
||||
IRI location = receipt.getLocation();
|
||||
if (location == null)
|
||||
{
|
||||
throw new SwordServerException("No Location found in Deposit Receipt; unable to send valid response");
|
||||
}
|
||||
|
||||
resp.setStatus(201); // Created
|
||||
if (this.config.returnDepositReceipt() && !receipt.isEmpty())
|
||||
{
|
||||
resp.setHeader("Content-Type", "application/atom+xml;type=entry");
|
||||
resp.setHeader("Location", location.toString());
|
||||
|
||||
// set the last modified header
|
||||
// like: Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
|
||||
Date lastModified = receipt.getLastModified() != null ? receipt.getLastModified() : new Date();
|
||||
resp.setHeader("Last-Modified", sdf.format(lastModified));
|
||||
|
||||
// to set the content-md5 header we need to write the output to
|
||||
// a string and checksum it
|
||||
StringWriter writer = new StringWriter();
|
||||
Entry responseEntry = receipt.getAbderaEntry();
|
||||
responseEntry.writeTo(writer);
|
||||
|
||||
// write the content-md5 header
|
||||
String md5 = ChecksumUtils.generateMD5(writer.toString().getBytes());
|
||||
resp.setHeader("Content-MD5", md5);
|
||||
|
||||
resp.getWriter().append(writer.toString());
|
||||
resp.getWriter().flush();
|
||||
}
|
||||
else
|
||||
{
|
||||
resp.setHeader("Location", location.toString());
|
||||
}
|
||||
}
|
||||
catch (SwordError se)
|
||||
{
|
||||
this.swordError(req, resp, se);
|
||||
}
|
||||
catch (SwordServerException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
catch (NoSuchAlgorithmException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
// authentication actually failed at the server end; not a SwordError, but
|
||||
// need to throw a 403 Forbidden
|
||||
resp.sendError(403);
|
||||
}
|
||||
}
|
||||
protected void addGenerator(DepositReceipt doc, SwordConfiguration config)
|
||||
{
|
||||
Element generator = this.getGenerator(this.config);
|
||||
if (generator != null)
|
||||
{
|
||||
doc.getWrappedEntry().addExtension(generator);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addGenerator(Feed doc, SwordConfiguration config)
|
||||
{
|
||||
Element generator = this.getGenerator(this.config);
|
||||
if (generator != null)
|
||||
{
|
||||
doc.addExtension(generator);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
public interface CollectionDepositManager
|
||||
{
|
||||
DepositReceipt createNew(String collectionURI, Deposit deposit, AuthCredentials auth, SwordConfiguration config) throws SwordError, SwordServerException, SwordAuthException;
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import org.apache.abdera.i18n.iri.IRI;
|
||||
import org.apache.abdera.model.Feed;
|
||||
|
||||
public interface CollectionListManager
|
||||
{
|
||||
Feed listCollectionContents(IRI collectionIRI, AuthCredentials auth, SwordConfiguration config) throws SwordServerException, SwordAuthException, SwordError;
|
||||
}
|
@@ -1,471 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import org.apache.abdera.i18n.iri.IRI;
|
||||
import org.apache.abdera.model.Element;
|
||||
import org.apache.abdera.model.Entry;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
public class ContainerAPI extends SwordAPIEndpoint
|
||||
{
|
||||
private static Logger log = Logger.getLogger(ContainerAPI.class);
|
||||
|
||||
private ContainerManager cm;
|
||||
private StatementManager sm;
|
||||
|
||||
public ContainerAPI(ContainerManager cm, StatementManager sm, SwordConfiguration config)
|
||||
{
|
||||
super(config);
|
||||
this.cm = cm;
|
||||
this.sm = sm;
|
||||
}
|
||||
|
||||
public void get(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
this.get(req, resp, true);
|
||||
}
|
||||
|
||||
public void get(HttpServletRequest req, HttpServletResponse resp, boolean sendBody)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
// do the initial authentication
|
||||
AuthCredentials auth = null;
|
||||
try
|
||||
{
|
||||
auth = this.getAuthCredentials(req);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
if (e.isRetry())
|
||||
{
|
||||
String s = "Basic realm=\"SWORD2\"";
|
||||
resp.setHeader("WWW-Authenticate", s);
|
||||
resp.setStatus(401);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// we allow content negotiation on this header
|
||||
Map<String, String> accept = this.getAcceptHeaders(req);
|
||||
String iri = this.getFullUrl(req);
|
||||
|
||||
// the content negotiation may be for the deposit receipt, OR for
|
||||
// the Statement
|
||||
if (this.cm.isStatementRequest(iri, accept, auth, this.config))
|
||||
{
|
||||
Statement statement = this.sm.getStatement(iri, accept, auth, this.config);
|
||||
|
||||
// set the content type
|
||||
resp.setHeader("Content-Type", statement.getContentType());
|
||||
|
||||
// set the last modified header
|
||||
// like: Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
|
||||
Date lastModified = statement.getLastModified() != null ? statement.getLastModified() : new Date();
|
||||
resp.setHeader("Last-Modified", sdf.format(lastModified));
|
||||
|
||||
// to set the content-md5 header we need to write the output to
|
||||
// a string and checksum it
|
||||
StringWriter writer = new StringWriter();
|
||||
statement.writeTo(writer);
|
||||
|
||||
// write the content-md5 header
|
||||
String md5 = ChecksumUtils.generateMD5(writer.toString().getBytes());
|
||||
resp.setHeader("Content-MD5", md5);
|
||||
|
||||
if (sendBody)
|
||||
{
|
||||
resp.getWriter().append(writer.toString());
|
||||
resp.getWriter().flush();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DepositReceipt receipt = this.cm.getEntry(iri, accept, auth, this.config);
|
||||
this.addGenerator(receipt, this.config);
|
||||
|
||||
IRI location = receipt.getLocation();
|
||||
resp.setHeader("Content-Type", "application/atom+xml;type=entry");
|
||||
resp.setHeader("Location", location.toString());
|
||||
|
||||
// set the last modified header
|
||||
// like: Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
|
||||
Date lastModified = receipt.getLastModified() != null ? receipt.getLastModified() : new Date();
|
||||
resp.setHeader("Last-Modified", sdf.format(lastModified));
|
||||
|
||||
// to set the content-md5 header we need to write the output to
|
||||
// a string and checksum it
|
||||
StringWriter writer = new StringWriter();
|
||||
Entry responseEntry = receipt.getAbderaEntry();
|
||||
responseEntry.writeTo(writer);
|
||||
|
||||
// write the content-md5 header
|
||||
String md5 = ChecksumUtils.generateMD5(writer.toString().getBytes());
|
||||
resp.setHeader("Content-MD5", md5);
|
||||
|
||||
if (sendBody)
|
||||
{
|
||||
resp.getWriter().append(writer.toString());
|
||||
resp.getWriter().flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SwordError se)
|
||||
{
|
||||
this.swordError(req, resp, se);
|
||||
}
|
||||
catch (SwordServerException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
catch (NoSuchAlgorithmException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
// authentication actually failed at the server end; not a SwordError, but
|
||||
// need to throw a 403 Forbidden
|
||||
resp.sendError(403);
|
||||
}
|
||||
}
|
||||
|
||||
public void head(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
this.get(req, resp, false);
|
||||
}
|
||||
|
||||
public void put(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
// do the initial authentication
|
||||
AuthCredentials auth = null;
|
||||
try
|
||||
{
|
||||
auth = this.getAuthCredentials(req);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
if (e.isRetry())
|
||||
{
|
||||
String s = "Basic realm=\"SWORD2\"";
|
||||
resp.setHeader("WWW-Authenticate", s);
|
||||
resp.setStatus(401);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// the first thing to do is determine what the deposit type is:
|
||||
String contentType = this.getContentType(req);
|
||||
boolean isMultipart = contentType.startsWith("multipart/related");
|
||||
boolean isEntryOnly = contentType.startsWith("application/atom+xml");
|
||||
|
||||
// get the In-Progress header
|
||||
boolean inProgress = this.getInProgress(req);
|
||||
|
||||
Deposit deposit = new Deposit();
|
||||
deposit.setInProgress(inProgress);
|
||||
String iri = this.getFullUrl(req);
|
||||
DepositReceipt receipt;
|
||||
|
||||
if (isMultipart)
|
||||
{
|
||||
this.addDepositPropertiesFromMultipart(deposit, req);
|
||||
|
||||
// defer to the implementation layer to update both the metadata and the media resource
|
||||
receipt = this.cm.replaceMetadataAndMediaResource(iri, deposit, auth, this.config);
|
||||
}
|
||||
else if (isEntryOnly)
|
||||
{
|
||||
// check that we have the right content type
|
||||
if (!(contentType.startsWith("application/atom+xml") || contentType.startsWith("application/atom+xml;type=entry")))
|
||||
{
|
||||
throw new SwordError(UriRegistry.ERROR_BAD_REQUEST, "Content-Type must be 'application/atom+xml' or 'application/atom+xml;type=entry'");
|
||||
}
|
||||
|
||||
this.addDepositPropertiesFromEntry(deposit, req);
|
||||
|
||||
// now defer to the implementation layer
|
||||
receipt = this.cm.replaceMetadata(iri, deposit, auth, this.config);
|
||||
}
|
||||
else
|
||||
{
|
||||
// some other sort of deposit which is not supported
|
||||
throw new SwordError(UriRegistry.ERROR_BAD_REQUEST, "PUT to Edit-IRI MUST be a multipart request or an Atom Entry");
|
||||
}
|
||||
|
||||
// prepare and return the response
|
||||
IRI location = receipt.getLocation();
|
||||
if (location == null)
|
||||
{
|
||||
throw new SwordServerException("No Location found in Deposit Receipt; unable to send valid response");
|
||||
}
|
||||
|
||||
if (this.config.returnDepositReceipt() && !receipt.isEmpty())
|
||||
{
|
||||
this.addGenerator(receipt, this.config);
|
||||
resp.setStatus(200);
|
||||
resp.setHeader("Content-Type", "application/atom+xml;type=entry");
|
||||
resp.setHeader("Location", location.toString());
|
||||
|
||||
// set the last modified header
|
||||
// like: Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
|
||||
Date lastModified = receipt.getLastModified() != null ? receipt.getLastModified() : new Date();
|
||||
resp.setHeader("Last-Modified", sdf.format(lastModified));
|
||||
|
||||
// to set the content-md5 header we need to write the output to
|
||||
// a string and checksum it
|
||||
StringWriter writer = new StringWriter();
|
||||
Entry responseEntry = receipt.getAbderaEntry();
|
||||
responseEntry.writeTo(writer);
|
||||
|
||||
// write the content-md5 header
|
||||
String md5 = ChecksumUtils.generateMD5(writer.toString().getBytes());
|
||||
resp.setHeader("Content-MD5", md5);
|
||||
|
||||
resp.getWriter().append(writer.toString());
|
||||
resp.getWriter().flush();
|
||||
}
|
||||
else
|
||||
{
|
||||
resp.setStatus(204);
|
||||
resp.setHeader("Location", location.toString());
|
||||
}
|
||||
}
|
||||
catch (SwordError se)
|
||||
{
|
||||
this.swordError(req, resp, se);
|
||||
}
|
||||
catch (SwordServerException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
catch (NoSuchAlgorithmException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
// authentication actually failed at the server end; not a SwordError, but
|
||||
// need to throw a 403 Forbidden
|
||||
resp.sendError(403);
|
||||
}
|
||||
}
|
||||
|
||||
public void post(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
// do the initial authentication
|
||||
AuthCredentials auth = null;
|
||||
try
|
||||
{
|
||||
auth = this.getAuthCredentials(req);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
if (e.isRetry())
|
||||
{
|
||||
String s = "Basic realm=\"SWORD2\"";
|
||||
resp.setHeader("WWW-Authenticate", s);
|
||||
resp.setStatus(401);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// the first thing to do is determine what the deposit type is:
|
||||
String contentType = this.getContentType(req);
|
||||
boolean isEntryOnly = contentType.startsWith("application/atom+xml");
|
||||
|
||||
// if neither of these content types are set, we may have an empty deposit
|
||||
// which is just providing instructions to the server (i.e. In-Progress is complete)
|
||||
|
||||
// Content-Length is zero in this case
|
||||
int contentLength = req.getContentLength();
|
||||
boolean headersOnly = contentLength == 0;
|
||||
|
||||
// get the common HTTP headers before leaping into the deposit type specific processes
|
||||
boolean inProgress = this.getInProgress(req);
|
||||
String iri = this.getFullUrl(req);
|
||||
|
||||
Deposit deposit = new Deposit();
|
||||
deposit.setInProgress(inProgress);
|
||||
DepositReceipt receipt;
|
||||
|
||||
// do the different kinds of deposit details extraction, and then delegate to the implementation
|
||||
// for handling
|
||||
if (isEntryOnly)
|
||||
{
|
||||
this.addDepositPropertiesFromEntry(deposit, req);
|
||||
receipt = this.cm.addMetadata(iri, deposit, auth, this.config);
|
||||
}
|
||||
else if (headersOnly)
|
||||
{
|
||||
receipt = this.cm.useHeaders(iri, deposit, auth, this.config);
|
||||
}
|
||||
else
|
||||
{
|
||||
// some other sort of deposit which is not supported (shouldn't ever get here)
|
||||
throw new SwordError(UriRegistry.ERROR_BAD_REQUEST);
|
||||
}
|
||||
|
||||
// prepare and return the response
|
||||
IRI location = receipt.getLocation();
|
||||
|
||||
// NOTE that in this case, no Location header is required, so the editIRI MAY be null
|
||||
if (this.config.returnDepositReceipt() && !receipt.isEmpty())
|
||||
{
|
||||
this.addGenerator(receipt, this.config);
|
||||
resp.setHeader("Content-Type", "application/atom+xml;type=entry");
|
||||
if (location != null)
|
||||
{
|
||||
resp.setHeader("Location", location.toString());
|
||||
}
|
||||
|
||||
// set the last modified header
|
||||
// like: Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
|
||||
Date lastModified = receipt.getLastModified() != null ? receipt.getLastModified() : new Date();
|
||||
resp.setHeader("Last-Modified", sdf.format(lastModified));
|
||||
|
||||
// to set the content-md5 header we need to write the output to
|
||||
// a string and checksum it
|
||||
StringWriter writer = new StringWriter();
|
||||
Entry responseEntry = receipt.getAbderaEntry();
|
||||
responseEntry.writeTo(writer);
|
||||
|
||||
// write the content-md5 header
|
||||
String md5 = ChecksumUtils.generateMD5(writer.toString().getBytes());
|
||||
resp.setHeader("Content-MD5", md5);
|
||||
|
||||
resp.getWriter().append(writer.toString());
|
||||
resp.getWriter().flush();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (location != null)
|
||||
{
|
||||
resp.setHeader("Location", location.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SwordError se)
|
||||
{
|
||||
this.swordError(req, resp, se);
|
||||
}
|
||||
catch (SwordServerException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
catch (NoSuchAlgorithmException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
// authentication actually failed at the server end; not a SwordError, but
|
||||
// need to throw a 403 Forbidden
|
||||
resp.sendError(403);
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
// do the initial authentication
|
||||
AuthCredentials auth = null;
|
||||
try
|
||||
{
|
||||
auth = this.getAuthCredentials(req);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
if (e.isRetry())
|
||||
{
|
||||
String s = "Basic realm=\"SWORD2\"";
|
||||
resp.setHeader("WWW-Authenticate", s);
|
||||
resp.setStatus(401);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
String uri = this.getFullUrl(req);
|
||||
|
||||
// send it to the implementation
|
||||
this.cm.deleteContainer(uri, auth, this.config);
|
||||
|
||||
// Not expecting any response, so if no error just return a 204
|
||||
resp.setStatus(204);
|
||||
}
|
||||
catch (SwordError se)
|
||||
{
|
||||
this.swordError(req, resp, se);
|
||||
}
|
||||
catch (SwordServerException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
// authentication actually failed at the server end; not a SwordError, but
|
||||
// need to throw a 403 Forbidden
|
||||
resp.sendError(403);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addGenerator(DepositReceipt doc, SwordConfiguration config)
|
||||
{
|
||||
Element generator = this.getGenerator(this.config);
|
||||
if (generator != null)
|
||||
{
|
||||
doc.getWrappedEntry().addExtension(generator);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,40 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface ContainerManager
|
||||
{
|
||||
DepositReceipt getEntry(String editIRI, Map<String, String> accept, AuthCredentials auth, SwordConfiguration config)
|
||||
throws SwordServerException, SwordError, SwordAuthException;
|
||||
|
||||
DepositReceipt replaceMetadata(String editIRI, Deposit deposit, AuthCredentials auth, SwordConfiguration config)
|
||||
throws SwordError, SwordServerException, SwordAuthException;
|
||||
|
||||
DepositReceipt replaceMetadataAndMediaResource(String editIRI, Deposit deposit, AuthCredentials auth, SwordConfiguration config)
|
||||
throws SwordError, SwordServerException, SwordAuthException;
|
||||
|
||||
DepositReceipt addMetadataAndResources(String editIRI, Deposit deposit, AuthCredentials auth, SwordConfiguration config)
|
||||
throws SwordError, SwordServerException, SwordAuthException;
|
||||
|
||||
DepositReceipt addMetadata(String editIRI, Deposit deposit, AuthCredentials auth, SwordConfiguration config)
|
||||
throws SwordError, SwordServerException, SwordAuthException;
|
||||
|
||||
DepositReceipt addResources(String editIRI, Deposit deposit, AuthCredentials auth, SwordConfiguration config)
|
||||
throws SwordError, SwordServerException, SwordAuthException;
|
||||
|
||||
void deleteContainer(String editIRI, AuthCredentials auth, SwordConfiguration config)
|
||||
throws SwordError, SwordServerException, SwordAuthException;
|
||||
|
||||
DepositReceipt useHeaders(String editIRI, Deposit deposit, AuthCredentials auth, SwordConfiguration config)
|
||||
throws SwordError, SwordServerException, SwordAuthException;
|
||||
|
||||
boolean isStatementRequest(String editIRI, Map<String, String> accept, AuthCredentials auth, SwordConfiguration config)
|
||||
throws SwordError, SwordServerException, SwordAuthException;
|
||||
}
|
@@ -1,185 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import org.apache.abdera.model.Entry;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class Deposit
|
||||
{
|
||||
private SwordEntry entry = null;
|
||||
private InputStream inputStream = null;
|
||||
private String filename;
|
||||
private String mimeType;
|
||||
private String slug = null;
|
||||
private String md5 = null;
|
||||
private String packaging;
|
||||
private boolean inProgress = false;
|
||||
private boolean metadataRelevant = true;
|
||||
private File file = null;
|
||||
|
||||
public Deposit() { }
|
||||
|
||||
public Deposit(Entry entry, InputStream inputStream, String filename, String mimeType, String slug, String md5,
|
||||
String packaging, boolean inProgress)
|
||||
{
|
||||
this.entry = new SwordEntry(entry);
|
||||
this.inputStream = inputStream;
|
||||
this.filename = filename;
|
||||
this.mimeType = mimeType;
|
||||
this.slug = slug;
|
||||
this.md5 = md5;
|
||||
this.packaging = packaging;
|
||||
this.inProgress = inProgress;
|
||||
}
|
||||
|
||||
public boolean isEntryOnly()
|
||||
{
|
||||
return this.entry != null && this.inputStream == null && this.file == null;
|
||||
}
|
||||
|
||||
public boolean isMultipart()
|
||||
{
|
||||
return this.entry != null && (this.inputStream != null || this.file != null);
|
||||
}
|
||||
|
||||
public boolean isBinaryOnly()
|
||||
{
|
||||
return this.entry == null && (this.inputStream != null || this.file != null);
|
||||
}
|
||||
|
||||
public File getFile()
|
||||
{
|
||||
return file;
|
||||
}
|
||||
|
||||
public void setFile(File file)
|
||||
{
|
||||
this.file = file;
|
||||
this.inputStream = null;
|
||||
}
|
||||
|
||||
public SwordEntry getSwordEntry()
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
|
||||
public void setEntry(Entry entry)
|
||||
{
|
||||
this.entry = new SwordEntry(entry);
|
||||
}
|
||||
|
||||
public InputStream getInputStream()
|
||||
throws SwordServerException
|
||||
{
|
||||
try
|
||||
{
|
||||
if (inputStream == null && file == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else if (inputStream == null && file != null)
|
||||
{
|
||||
return new FileInputStream(this.file);
|
||||
}
|
||||
else if (inputStream != null)
|
||||
{
|
||||
return inputStream;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
throw new SwordServerException(e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new SwordServerException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setInputStream(InputStream inputStream)
|
||||
{
|
||||
this.inputStream = inputStream;
|
||||
}
|
||||
|
||||
public String getFilename()
|
||||
{
|
||||
return filename;
|
||||
}
|
||||
|
||||
public void setFilename(String filename)
|
||||
{
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
public String getMimeType()
|
||||
{
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
public void setMimeType(String mimeType)
|
||||
{
|
||||
this.mimeType = mimeType;
|
||||
}
|
||||
|
||||
public String getSlug()
|
||||
{
|
||||
return slug;
|
||||
}
|
||||
|
||||
public void setSlug(String slug)
|
||||
{
|
||||
this.slug = slug;
|
||||
}
|
||||
|
||||
public String getMd5()
|
||||
{
|
||||
return md5;
|
||||
}
|
||||
|
||||
public void setMd5(String md5)
|
||||
{
|
||||
this.md5 = md5;
|
||||
}
|
||||
|
||||
public String getPackaging()
|
||||
{
|
||||
return packaging;
|
||||
}
|
||||
|
||||
public void setPackaging(String packaging)
|
||||
{
|
||||
this.packaging = packaging;
|
||||
}
|
||||
|
||||
public boolean isInProgress()
|
||||
{
|
||||
return inProgress;
|
||||
}
|
||||
|
||||
public void setInProgress(boolean inProgress)
|
||||
{
|
||||
this.inProgress = inProgress;
|
||||
}
|
||||
|
||||
public boolean isMetadataRelevant()
|
||||
{
|
||||
return metadataRelevant;
|
||||
}
|
||||
|
||||
public void setMetadataRelevant(boolean metadataRelevant)
|
||||
{
|
||||
this.metadataRelevant = metadataRelevant;
|
||||
}
|
||||
}
|
@@ -1,297 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import org.apache.abdera.Abdera;
|
||||
import org.apache.abdera.i18n.iri.IRI;
|
||||
import org.apache.abdera.model.Element;
|
||||
import org.apache.abdera.model.Entry;
|
||||
import org.apache.abdera.model.ExtensibleElement;
|
||||
import org.apache.abdera.model.Link;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DepositReceipt
|
||||
{
|
||||
private List<String> packagingFormats = new ArrayList<String>();
|
||||
private IRI editIRI = null;
|
||||
private IRI seIRI = null;
|
||||
private IRI emIRI = null;
|
||||
private IRI feedIRI = null;
|
||||
private IRI location = null;
|
||||
private Entry entry;
|
||||
private Map<String, String> statements = new HashMap<String, String>();
|
||||
private String treatment = null;
|
||||
private String verboseDescription = null;
|
||||
private String splashUri = null;
|
||||
private String originalDepositUri = null;
|
||||
private String originalDepositType = null;
|
||||
private Map<String, String> derivedResources = new HashMap<String, String>();
|
||||
private boolean empty = false;
|
||||
private Date lastModified = null;
|
||||
|
||||
public DepositReceipt()
|
||||
{
|
||||
Abdera abdera = new Abdera();
|
||||
this.entry = abdera.newEntry();
|
||||
}
|
||||
|
||||
public Entry getWrappedEntry()
|
||||
{
|
||||
return this.entry;
|
||||
}
|
||||
|
||||
public Entry getAbderaEntry()
|
||||
{
|
||||
Entry abderaEntry = (Entry) this.entry.clone();
|
||||
|
||||
// use the edit iri as the id
|
||||
abderaEntry.setId(this.editIRI.toString());
|
||||
|
||||
// add the Edit IRI Link
|
||||
if (this.editIRI != null)
|
||||
{
|
||||
abderaEntry.addLink(this.editIRI.toString(), "edit");
|
||||
}
|
||||
|
||||
// add the Sword Edit IRI link
|
||||
if (this.seIRI != null)
|
||||
{
|
||||
abderaEntry.addLink(this.seIRI.toString(), UriRegistry.REL_SWORD_EDIT);
|
||||
}
|
||||
|
||||
// add the atom formatted feed
|
||||
if (this.feedIRI != null)
|
||||
{
|
||||
Link fl = abderaEntry.addLink(this.feedIRI.toString(), "edit-media");
|
||||
fl.setMimeType("application/atom+xml;type=feed");
|
||||
}
|
||||
|
||||
// add the edit-media link
|
||||
if (this.emIRI != null)
|
||||
{
|
||||
abderaEntry.addLink(this.emIRI.toString(), "edit-media");
|
||||
}
|
||||
|
||||
// add the packaging formats
|
||||
for (String pf : this.packagingFormats)
|
||||
{
|
||||
abderaEntry.addSimpleExtension(UriRegistry.SWORD_PACKAGING, pf);
|
||||
}
|
||||
|
||||
// add the statement URIs
|
||||
for (String statement : this.statements.keySet())
|
||||
{
|
||||
Link link = abderaEntry.addLink(statement, UriRegistry.REL_STATEMENT);
|
||||
link.setMimeType(this.statements.get(statement));
|
||||
}
|
||||
|
||||
if (this.treatment != null)
|
||||
{
|
||||
abderaEntry.addSimpleExtension(UriRegistry.SWORD_TREATMENT, this.treatment);
|
||||
}
|
||||
|
||||
if (this.verboseDescription != null)
|
||||
{
|
||||
abderaEntry.addSimpleExtension(UriRegistry.SWORD_VERBOSE_DESCRIPTION, this.verboseDescription);
|
||||
}
|
||||
|
||||
if (this.splashUri == null)
|
||||
{
|
||||
abderaEntry.addLink(this.splashUri, "alternate");
|
||||
}
|
||||
|
||||
if (this.originalDepositUri != null)
|
||||
{
|
||||
Link link = abderaEntry.addLink(this.originalDepositUri, UriRegistry.REL_ORIGINAL_DEPOSIT);
|
||||
if (this.originalDepositType != null)
|
||||
{
|
||||
link.setMimeType(this.originalDepositType);
|
||||
}
|
||||
}
|
||||
|
||||
for (String uri : this.derivedResources.keySet())
|
||||
{
|
||||
Link link = abderaEntry.addLink(uri, UriRegistry.REL_DERIVED_RESOURCE);
|
||||
if (this.derivedResources.get(uri) != null)
|
||||
{
|
||||
link.setMimeType(this.derivedResources.get(uri));
|
||||
}
|
||||
}
|
||||
|
||||
return abderaEntry;
|
||||
}
|
||||
|
||||
public Date getLastModified()
|
||||
{
|
||||
return lastModified;
|
||||
}
|
||||
|
||||
public void setLastModified(Date lastModified)
|
||||
{
|
||||
this.lastModified = lastModified;
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return empty;
|
||||
}
|
||||
|
||||
public void setEmpty(boolean empty)
|
||||
{
|
||||
this.empty = empty;
|
||||
}
|
||||
|
||||
public void setMediaFeedIRI(IRI feedIRI)
|
||||
{
|
||||
this.feedIRI = feedIRI;
|
||||
}
|
||||
|
||||
public void setEditMediaIRI(IRI emIRI)
|
||||
{
|
||||
this.emIRI = emIRI;
|
||||
}
|
||||
|
||||
public void setEditIRI(IRI editIRI)
|
||||
{
|
||||
this.editIRI = editIRI;
|
||||
|
||||
// set the SE-IRI as the same if it has not already been set
|
||||
if (this.seIRI == null)
|
||||
{
|
||||
this.seIRI = editIRI;
|
||||
}
|
||||
}
|
||||
|
||||
public IRI getLocation()
|
||||
{
|
||||
return this.location == null ? this.editIRI : this.location;
|
||||
}
|
||||
|
||||
public void setLocation(IRI location)
|
||||
{
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public IRI getEditIRI()
|
||||
{
|
||||
return this.editIRI;
|
||||
}
|
||||
|
||||
public IRI getSwordEditIRI()
|
||||
{
|
||||
return this.seIRI;
|
||||
}
|
||||
|
||||
public void setSwordEditIRI(IRI seIRI)
|
||||
{
|
||||
this.seIRI = seIRI;
|
||||
|
||||
// set the Edit-IRI the same if it has not already been set
|
||||
if (this.editIRI == null)
|
||||
{
|
||||
this.editIRI = seIRI;
|
||||
}
|
||||
}
|
||||
|
||||
public void setContent(IRI href, String mediaType)
|
||||
{
|
||||
this.entry.setContent(href, mediaType);
|
||||
}
|
||||
|
||||
public void addEditMediaIRI(IRI href)
|
||||
{
|
||||
this.entry.addLink(href.toString(), "edit-media");
|
||||
}
|
||||
|
||||
public void addEditMediaIRI(IRI href, String mediaType)
|
||||
{
|
||||
Abdera abdera = new Abdera();
|
||||
Link link = abdera.getFactory().newLink();
|
||||
link.setHref(href.toString());
|
||||
link.setRel("edit-media");
|
||||
link.setMimeType(mediaType);
|
||||
this.entry.addLink(link);
|
||||
}
|
||||
|
||||
public void addEditMediaFeedIRI(IRI href)
|
||||
{
|
||||
this.addEditMediaIRI(href, "application/atom+xml;type=feed");
|
||||
}
|
||||
|
||||
public void setPackaging(List<String> packagingFormats)
|
||||
{
|
||||
this.packagingFormats = packagingFormats;
|
||||
}
|
||||
|
||||
public void addPackaging(String packagingFormat)
|
||||
{
|
||||
this.packagingFormats.add(packagingFormat);
|
||||
}
|
||||
|
||||
public void setOREStatementURI(String statement)
|
||||
{
|
||||
this.setStatementURI("application/rdf+xml", statement);
|
||||
}
|
||||
|
||||
public void setAtomStatementURI(String statement)
|
||||
{
|
||||
this.setStatementURI("application/atom+xml;type=feed", statement);
|
||||
}
|
||||
|
||||
public void setStatementURI(String type, String statement)
|
||||
{
|
||||
this.statements.put(statement, type);
|
||||
}
|
||||
|
||||
public Element addSimpleExtension(QName qname, String value)
|
||||
{
|
||||
return this.entry.addSimpleExtension(qname, value);
|
||||
}
|
||||
|
||||
public Element addDublinCore(String element, String value)
|
||||
{
|
||||
return this.entry.addSimpleExtension(new QName(UriRegistry.DC_NAMESPACE, element), value);
|
||||
}
|
||||
|
||||
public void setTreatment(String treatment)
|
||||
{
|
||||
this.treatment = treatment;
|
||||
}
|
||||
|
||||
public void setVerboseDescription(String verboseDescription)
|
||||
{
|
||||
this.verboseDescription = verboseDescription;
|
||||
}
|
||||
|
||||
public void setSplashUri(String splashUri)
|
||||
{
|
||||
this.splashUri = splashUri;
|
||||
}
|
||||
|
||||
public void setOriginalDeposit(String originalDepositUri, String originalDepositType)
|
||||
{
|
||||
this.originalDepositUri = originalDepositUri;
|
||||
this.originalDepositType = originalDepositType;
|
||||
}
|
||||
|
||||
public void setDerivedResources(Map<String, String> derivedResources)
|
||||
{
|
||||
this.derivedResources = derivedResources;
|
||||
}
|
||||
|
||||
public void addDerivedResource(String resourceUri, String resourceType)
|
||||
{
|
||||
this.derivedResources.put(resourceUri, resourceType);
|
||||
}
|
||||
}
|
@@ -1,142 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import nu.xom.Attribute;
|
||||
import nu.xom.Document;
|
||||
import nu.xom.Element;
|
||||
import nu.xom.Serializer;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.Writer;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ErrorDocument
|
||||
{
|
||||
private String errorUri;
|
||||
private Map<String, Integer> errorCodes = new HashMap<String, Integer>();
|
||||
private String summary = null;
|
||||
private String verboseDescription = null;
|
||||
private int status;
|
||||
|
||||
public ErrorDocument(String errorUri)
|
||||
{
|
||||
this(errorUri, -1, null, null);
|
||||
}
|
||||
|
||||
public ErrorDocument(String errorUri, int status)
|
||||
{
|
||||
this(errorUri, status, null, null);
|
||||
}
|
||||
|
||||
public ErrorDocument(String errorUri, String verboseDescription)
|
||||
{
|
||||
this(errorUri, -1, null, verboseDescription);
|
||||
}
|
||||
|
||||
public ErrorDocument(String errorUri, int status, String verboseDescription)
|
||||
{
|
||||
this(errorUri, status, null, verboseDescription);
|
||||
}
|
||||
|
||||
public ErrorDocument(String errorUri, int status, String summary, String verboseDescription)
|
||||
{
|
||||
// set up the error codes mapping
|
||||
this.errorCodes.put(UriRegistry.ERROR_BAD_REQUEST, 400); // bad request
|
||||
this.errorCodes.put(UriRegistry.ERROR_CHECKSUM_MISMATCH, 412); // precondition failed
|
||||
this.errorCodes.put(UriRegistry.ERROR_CONTENT, 415); // unsupported media type
|
||||
this.errorCodes.put(UriRegistry.ERROR_MEDIATION_NOT_ALLOWED, 412); // precondition failed
|
||||
this.errorCodes.put(UriRegistry.ERROR_METHOD_NOT_ALLOWED, 405); // method not allowed
|
||||
this.errorCodes.put(UriRegistry.ERROR_TARGET_OWNER_UNKNOWN, 403); // forbidden
|
||||
this.errorCodes.put(UriRegistry.ERROR_MAX_UPLOAD_SIZE_EXCEEDED, 413); // forbidden
|
||||
|
||||
this.errorUri = errorUri;
|
||||
this.summary = summary;
|
||||
this.verboseDescription = verboseDescription;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public int getStatus()
|
||||
{
|
||||
if (this.status > -1)
|
||||
{
|
||||
return this.status;
|
||||
}
|
||||
|
||||
if (this.errorCodes.containsKey(errorUri))
|
||||
{
|
||||
return this.errorCodes.get(errorUri);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 400; // bad request
|
||||
}
|
||||
}
|
||||
|
||||
public void writeTo(Writer out, SwordConfiguration config)
|
||||
throws IOException, SwordServerException
|
||||
{
|
||||
// do the XML serialisation
|
||||
Element error = new Element("sword:error", UriRegistry.SWORD_TERMS_NAMESPACE);
|
||||
error.addAttribute(new Attribute("href", this.errorUri));
|
||||
|
||||
// write some boiler-plate text into the document
|
||||
Element title = new Element("atom:title", UriRegistry.ATOM_NAMESPACE);
|
||||
Element updates = new Element("atom:updated", UriRegistry.ATOM_NAMESPACE);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||
updates.appendChild(sdf.format(new Date()));
|
||||
Element generator = new Element("atom:generator", UriRegistry.ATOM_NAMESPACE);
|
||||
generator.addAttribute(new Attribute("uri", config.generator()));
|
||||
generator.addAttribute(new Attribute("version", config.generatorVersion()));
|
||||
if (config.administratorEmail() != null)
|
||||
{
|
||||
generator.appendChild(config.administratorEmail());
|
||||
}
|
||||
Element treatment = new Element("sword:treatment", UriRegistry.SWORD_TERMS_NAMESPACE);
|
||||
treatment.appendChild("Processing failed");
|
||||
|
||||
error.appendChild(title);
|
||||
error.appendChild(updates);
|
||||
error.appendChild(generator);
|
||||
error.appendChild(treatment);
|
||||
|
||||
// now add the operational bits
|
||||
if (this.summary != null)
|
||||
{
|
||||
Element summary = new Element("atom:summary", UriRegistry.ATOM_NAMESPACE);
|
||||
summary.appendChild(this.summary);
|
||||
error.appendChild(summary);
|
||||
}
|
||||
|
||||
if (this.verboseDescription != null)
|
||||
{
|
||||
Element vd = new Element("sword:verboseDescription", UriRegistry.SWORD_TERMS_NAMESPACE);
|
||||
vd.appendChild(this.verboseDescription);
|
||||
error.appendChild(vd);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// now get it written out
|
||||
Document doc = new Document(error);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
Serializer serializer = new Serializer(baos, "ISO-8859-1");
|
||||
serializer.write(doc);
|
||||
out.write(baos.toString());
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
throw new SwordServerException(e);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,94 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
|
||||
public class MediaResource
|
||||
{
|
||||
private String packaging = UriRegistry.PACKAGE_SIMPLE_ZIP;
|
||||
private String contentType = "application/octet-stream";
|
||||
private InputStream inputStream = null;
|
||||
private boolean unpackaged = false;
|
||||
private String contentMD5;
|
||||
private Date lastModified;
|
||||
|
||||
public MediaResource(InputStream in, String contentType, String packaging)
|
||||
{
|
||||
this(in, contentType, packaging, false);
|
||||
}
|
||||
|
||||
public MediaResource(InputStream in, String contentType, String packaging, boolean unpackaged)
|
||||
{
|
||||
this.inputStream = in;
|
||||
this.contentType = contentType;
|
||||
this.packaging = packaging;
|
||||
this.unpackaged = unpackaged;
|
||||
}
|
||||
|
||||
public String getContentMD5()
|
||||
{
|
||||
return contentMD5;
|
||||
}
|
||||
|
||||
public void setContentMD5(String contentMD5)
|
||||
{
|
||||
this.contentMD5 = contentMD5;
|
||||
}
|
||||
|
||||
public Date getLastModified()
|
||||
{
|
||||
return lastModified;
|
||||
}
|
||||
|
||||
public void setLastModified(Date lastModified)
|
||||
{
|
||||
this.lastModified = lastModified;
|
||||
}
|
||||
|
||||
public boolean isUnpackaged()
|
||||
{
|
||||
return unpackaged;
|
||||
}
|
||||
|
||||
public void setUnpackaged(boolean unpackaged)
|
||||
{
|
||||
this.unpackaged = unpackaged;
|
||||
}
|
||||
|
||||
public String getPackaging()
|
||||
{
|
||||
return packaging;
|
||||
}
|
||||
|
||||
public InputStream getInputStream()
|
||||
{
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
public void setInputStream(InputStream inputStream)
|
||||
{
|
||||
this.inputStream = inputStream;
|
||||
}
|
||||
|
||||
public String getContentType()
|
||||
{
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public void setContentType(String contentType)
|
||||
{
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
public void setPackaging(String packaging)
|
||||
{
|
||||
this.packaging = packaging;
|
||||
}
|
||||
}
|
@@ -1,346 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import org.apache.abdera.i18n.iri.IRI;
|
||||
import org.apache.abdera.model.Element;
|
||||
import org.apache.abdera.model.Entry;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
public class MediaResourceAPI extends SwordAPIEndpoint
|
||||
{
|
||||
private static Logger log = Logger.getLogger(MediaResourceAPI.class);
|
||||
|
||||
protected MediaResourceManager mrm;
|
||||
|
||||
public MediaResourceAPI(MediaResourceManager mrm, SwordConfiguration config)
|
||||
{
|
||||
super(config);
|
||||
this.mrm = mrm;
|
||||
}
|
||||
|
||||
public void get(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
this.get(req, resp, true);
|
||||
}
|
||||
|
||||
public void get(HttpServletRequest req, HttpServletResponse resp, boolean sendBody)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
// do the initial authentication
|
||||
AuthCredentials auth = null;
|
||||
try
|
||||
{
|
||||
auth = this.getAuthCredentials(req);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
if (e.isRetry())
|
||||
{
|
||||
String s = "Basic realm=\"SWORD2\"";
|
||||
resp.setHeader("WWW-Authenticate", s);
|
||||
resp.setStatus(401);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// get all of the Accept- headers out for content negotiation
|
||||
Map<String, String> acceptHeaders = this.getAcceptHeaders(req);
|
||||
|
||||
// get the original request URI
|
||||
String editMediaURI = this.getFullUrl(req);
|
||||
|
||||
// delegate to the implementation to get the resource representation
|
||||
MediaResource resource = this.mrm.getMediaResourceRepresentation(editMediaURI, acceptHeaders, auth, this.config);
|
||||
|
||||
// now deliver the resource representation to the client
|
||||
|
||||
// if this is a packaged resource, then write the package header
|
||||
if (!resource.isUnpackaged())
|
||||
{
|
||||
String packaging = resource.getPackaging();
|
||||
if (packaging == null || "".equals(packaging))
|
||||
{
|
||||
packaging = UriRegistry.PACKAGE_SIMPLE_ZIP;
|
||||
}
|
||||
resp.setHeader("Packaging", packaging);
|
||||
}
|
||||
|
||||
String contentType = resource.getContentType();
|
||||
if (contentType == null || "".equals(contentType))
|
||||
{
|
||||
contentType = "application/octet-stream";
|
||||
}
|
||||
resp.setHeader("Content-Type", contentType);
|
||||
|
||||
// set the last modified header
|
||||
// like: Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
|
||||
Date lastModified = resource.getLastModified() != null ? resource.getLastModified() : new Date();
|
||||
resp.setHeader("Last-Modified", sdf.format(lastModified));
|
||||
|
||||
// to set the content-md5 header we need to write the output to
|
||||
// a string and checksum it
|
||||
String md5 = resource.getContentMD5();
|
||||
resp.setHeader("Content-MD5", md5);
|
||||
|
||||
if (sendBody)
|
||||
{
|
||||
OutputStream out = resp.getOutputStream();
|
||||
InputStream in = resource.getInputStream();
|
||||
this.copyInputToOutput(in, out);
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
catch (SwordError se)
|
||||
{
|
||||
this.swordError(req, resp, se);
|
||||
return;
|
||||
}
|
||||
catch (SwordServerException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
// authentication actually failed at the server end; not a SwordError, but
|
||||
// need to throw a 403 Forbidden
|
||||
resp.sendError(403);
|
||||
}
|
||||
}
|
||||
|
||||
public void head(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
this.get(req, resp, false);
|
||||
}
|
||||
|
||||
public void put(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
// do the initial authentication
|
||||
AuthCredentials auth = null;
|
||||
try
|
||||
{
|
||||
auth = this.getAuthCredentials(req);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
if (e.isRetry())
|
||||
{
|
||||
String s = "Basic realm=\"SWORD2\"";
|
||||
resp.setHeader("WWW-Authenticate", s);
|
||||
resp.setStatus(401);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
String editMediaIRI = this.getFullUrl(req);
|
||||
Deposit deposit = new Deposit();
|
||||
|
||||
// add the properties from the binary deposit
|
||||
this.addDepositPropertiesFromBinary(deposit, req);
|
||||
|
||||
// now fire the deposit object into the implementation
|
||||
DepositReceipt receipt = this.mrm.replaceMediaResource(editMediaIRI, deposit, auth, this.config);
|
||||
|
||||
// no response is expected, if no errors get thrown we just return a success: 204 No Content
|
||||
// and the appropriate location header
|
||||
resp.setHeader("Location", receipt.getLocation().toString());
|
||||
resp.setStatus(204);
|
||||
}
|
||||
catch (SwordError se)
|
||||
{
|
||||
this.swordError(req, resp, se);
|
||||
}
|
||||
catch (SwordServerException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
// authentication actually failed at the server end; not a SwordError, but
|
||||
// need to throw a 403 Forbidden
|
||||
resp.sendError(403);
|
||||
}
|
||||
}
|
||||
|
||||
public void post(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
// do the initial authentication
|
||||
AuthCredentials auth = null;
|
||||
try
|
||||
{
|
||||
auth = this.getAuthCredentials(req);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
if (e.isRetry())
|
||||
{
|
||||
String s = "Basic realm=\"SWORD2\"";
|
||||
resp.setHeader("WWW-Authenticate", s);
|
||||
resp.setStatus(401);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// the first thing to do is determine what the deposit type is:
|
||||
String contentType = this.getContentType(req);
|
||||
boolean isMultipart = contentType.startsWith("multipart/related");
|
||||
String uri = this.getFullUrl(req);
|
||||
|
||||
Deposit deposit = new Deposit();
|
||||
|
||||
if (isMultipart)
|
||||
{
|
||||
this.addDepositPropertiesFromMultipart(deposit, req);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.addDepositPropertiesFromBinary(deposit, req);
|
||||
}
|
||||
|
||||
// this method has a special header (Metadata-Relevant) which we need to pull out
|
||||
boolean metadataRelevant = this.getMetadataRelevant(req);
|
||||
deposit.setMetadataRelevant(metadataRelevant);
|
||||
|
||||
// now send the deposit to the implementation for processing
|
||||
DepositReceipt receipt = this.mrm.addResource(uri, deposit, auth, this.config);
|
||||
|
||||
// prepare and return the response
|
||||
IRI location = receipt.getLocation();
|
||||
if (location == null)
|
||||
{
|
||||
throw new SwordServerException("No Edit-IRI found in Deposit Receipt; unable to send valid response");
|
||||
}
|
||||
|
||||
resp.setStatus(201); // Created
|
||||
if (this.config.returnDepositReceipt() && !receipt.isEmpty())
|
||||
{
|
||||
this.addGenerator(receipt, this.config);
|
||||
resp.setHeader("Content-Type", "application/atom+xml;type=entry");
|
||||
resp.setHeader("Location", location.toString());
|
||||
Entry responseEntry = receipt.getAbderaEntry();
|
||||
responseEntry.writeTo(resp.getWriter());
|
||||
resp.getWriter().flush();
|
||||
}
|
||||
else
|
||||
{
|
||||
resp.setHeader("Location", location.toString());
|
||||
}
|
||||
}
|
||||
catch (SwordError se)
|
||||
{
|
||||
this.swordError(req, resp, se);
|
||||
return;
|
||||
}
|
||||
catch (SwordServerException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
// authentication actually failed at the server end; not a SwordError, but
|
||||
// need to throw a 403 Forbidden
|
||||
resp.sendError(403);
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
// do the initial authentication
|
||||
AuthCredentials auth = null;
|
||||
try
|
||||
{
|
||||
auth = this.getAuthCredentials(req);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
if (e.isRetry())
|
||||
{
|
||||
String s = "Basic realm=\"SWORD2\"";
|
||||
resp.setHeader("WWW-Authenticate", s);
|
||||
resp.setStatus(401);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
String editMediaIRI = this.getFullUrl(req);
|
||||
|
||||
// delegate to the implementation
|
||||
this.mrm.deleteMediaResource(editMediaIRI, auth, this.config);
|
||||
|
||||
// no response is expected, if no errors get thrown then we just return a success: 204 No Content
|
||||
resp.setStatus(204);
|
||||
}
|
||||
catch (SwordError se)
|
||||
{
|
||||
this.swordError(req, resp, se);
|
||||
}
|
||||
catch (SwordServerException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
// authentication actually failed at the server end; not a SwordError, but
|
||||
// need to throw a 403 Forbidden
|
||||
resp.sendError(403);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addGenerator(DepositReceipt doc, SwordConfiguration config)
|
||||
{
|
||||
Element generator = this.getGenerator(this.config);
|
||||
if (generator != null)
|
||||
{
|
||||
doc.getWrappedEntry().addExtension(generator);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface MediaResourceManager
|
||||
{
|
||||
MediaResource getMediaResourceRepresentation(String uri, Map<String, String> accept, AuthCredentials auth, SwordConfiguration config)
|
||||
throws SwordError, SwordServerException, SwordAuthException;
|
||||
|
||||
DepositReceipt replaceMediaResource(String uri, Deposit deposit, AuthCredentials auth, SwordConfiguration config)
|
||||
throws SwordError, SwordServerException, SwordAuthException;
|
||||
|
||||
void deleteMediaResource(String uri, AuthCredentials auth, SwordConfiguration config)
|
||||
throws SwordError, SwordServerException, SwordAuthException;
|
||||
|
||||
DepositReceipt addResource(String uri, Deposit deposit, AuthCredentials auth, SwordConfiguration config)
|
||||
throws SwordError, SwordServerException, SwordAuthException;
|
||||
}
|
@@ -1,106 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import com.hp.hpl.jena.rdf.model.Model;
|
||||
import com.hp.hpl.jena.rdf.model.ModelFactory;
|
||||
import com.hp.hpl.jena.rdf.model.Property;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
import com.hp.hpl.jena.vocabulary.RDF;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Writer;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
public class OREStatement extends Statement
|
||||
{
|
||||
private String remUri;
|
||||
private String aggUri;
|
||||
|
||||
public OREStatement(String remUri, String aggUri)
|
||||
{
|
||||
this.remUri = remUri;
|
||||
this.aggUri = aggUri;
|
||||
this.contentType = "application/rdf+xml";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(Writer out)
|
||||
throws IOException
|
||||
{
|
||||
// create the default model (in memory) to start with
|
||||
Model model = ModelFactory.createDefaultModel();
|
||||
|
||||
// create the resource map in the model
|
||||
Resource rem = model.createResource(this.remUri);
|
||||
rem.addProperty(RDF.type, model.createResource(UriRegistry.ORE_NAMESPACE + "ResourceMap"));
|
||||
|
||||
// create the aggregation
|
||||
Resource agg = model.createResource(this.aggUri);
|
||||
agg.addProperty(RDF.type, model.createResource(UriRegistry.ORE_NAMESPACE + "Aggregation"));
|
||||
|
||||
// add the aggregation to the resource (and vice versa)
|
||||
rem.addProperty(model.createProperty(UriRegistry.ORE_NAMESPACE + "describes"), agg);
|
||||
agg.addProperty(model.createProperty(UriRegistry.ORE_NAMESPACE + "isDescribedBy"), rem);
|
||||
|
||||
// now go through and add all the ResourceParts as aggregated resources
|
||||
for (ResourcePart rp : this.resources)
|
||||
{
|
||||
Resource part = model.createResource(rp.getUri());
|
||||
part.addProperty(RDF.type, model.createResource(UriRegistry.ORE_NAMESPACE + "AggregatedResource"));
|
||||
agg.addProperty(model.createProperty(UriRegistry.ORE_NAMESPACE + "aggregates"), part);
|
||||
}
|
||||
|
||||
// now go through all the original deposits and add them as both aggregated
|
||||
// resources and as originalDeposits (with all the trimmings)
|
||||
for (OriginalDeposit od : this.originalDeposits)
|
||||
{
|
||||
Resource deposit = model.createResource(od.getUri());
|
||||
deposit.addProperty(RDF.type, model.createResource(UriRegistry.ORE_NAMESPACE + "AggregatedResource"));
|
||||
if (od.getDepositedBy() != null)
|
||||
{
|
||||
deposit.addLiteral(model.createProperty(UriRegistry.SWORD_DEPOSITED_BY), od.getDepositedBy());
|
||||
}
|
||||
|
||||
if (od.getDepositedOnBehalfOf() != null)
|
||||
{
|
||||
deposit.addLiteral(model.createProperty(UriRegistry.SWORD_DEPOSITED_ON_BEHALF_OF), od.getDepositedOnBehalfOf());
|
||||
}
|
||||
|
||||
if (od.getDepositedOn() != null)
|
||||
{
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||
deposit.addLiteral(model.createProperty(UriRegistry.SWORD_DEPOSITED_ON), sdf.format(od.getDepositedOn()));
|
||||
}
|
||||
|
||||
for (String packaging : od.getPackaging())
|
||||
{
|
||||
deposit.addLiteral(model.createProperty(UriRegistry.SWORD_PACKAGING.toString()), packaging);
|
||||
}
|
||||
|
||||
agg.addProperty(model.createProperty(UriRegistry.ORE_NAMESPACE + "aggregates"), deposit);
|
||||
agg.addProperty(model.createProperty(UriRegistry.SWORD_ORIGINAL_DEPOSIT), deposit);
|
||||
}
|
||||
|
||||
// now add the state information
|
||||
for (String state : this.states.keySet())
|
||||
{
|
||||
Resource s = model.createResource(state);
|
||||
if (this.states.get(state) != null)
|
||||
{
|
||||
s.addProperty(model.createProperty(UriRegistry.SWORD_STATE_DESCRIPTION), this.states.get(state));
|
||||
}
|
||||
agg.addProperty(model.createProperty(UriRegistry.SWORD_STATE), s);
|
||||
}
|
||||
|
||||
// write the model directly to the output
|
||||
model.write(out, "RDF/XML");
|
||||
}
|
||||
}
|
@@ -1,79 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class OriginalDeposit extends ResourcePart
|
||||
{
|
||||
private List<String> packaging;
|
||||
private Date depositedOn;
|
||||
private String depositedBy;
|
||||
private String depositedOnBehalfOf;
|
||||
|
||||
public OriginalDeposit(String uri)
|
||||
{
|
||||
this(uri, new ArrayList<String>(), null, null, null);
|
||||
}
|
||||
|
||||
public OriginalDeposit(String uri, List<String> packaging, Date depositedOn, String depositedBy, String depositedOnBehalfOf)
|
||||
{
|
||||
super(uri);
|
||||
this.packaging = packaging;
|
||||
this.depositedOn = depositedOn;
|
||||
this.depositedBy = depositedBy;
|
||||
this.depositedOnBehalfOf = depositedOnBehalfOf;
|
||||
}
|
||||
|
||||
public String getUri()
|
||||
{
|
||||
return uri;
|
||||
}
|
||||
|
||||
public List<String> getPackaging()
|
||||
{
|
||||
return packaging;
|
||||
}
|
||||
|
||||
public void setPackaging(List<String> packaging)
|
||||
{
|
||||
this.packaging = packaging;
|
||||
}
|
||||
|
||||
public Date getDepositedOn()
|
||||
{
|
||||
return depositedOn;
|
||||
}
|
||||
|
||||
public void setDepositedOn(Date depositedOn)
|
||||
{
|
||||
this.depositedOn = depositedOn;
|
||||
}
|
||||
|
||||
public String getDepositedBy()
|
||||
{
|
||||
return depositedBy;
|
||||
}
|
||||
|
||||
public void setDepositedBy(String depositedBy)
|
||||
{
|
||||
this.depositedBy = depositedBy;
|
||||
}
|
||||
|
||||
public String getDepositedOnBehalfOf()
|
||||
{
|
||||
return depositedOnBehalfOf;
|
||||
}
|
||||
|
||||
public void setDepositedOnBehalfOf(String depositedOnBehalfOf)
|
||||
{
|
||||
this.depositedOnBehalfOf = depositedOnBehalfOf;
|
||||
}
|
||||
}
|
@@ -1,48 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ResourcePart
|
||||
{
|
||||
protected String uri;
|
||||
protected String mediaType;
|
||||
protected Map<String, String> properties = new HashMap<String, String>();
|
||||
|
||||
public ResourcePart(String uri)
|
||||
{
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public String getUri()
|
||||
{
|
||||
return uri;
|
||||
}
|
||||
|
||||
public String getMediaType()
|
||||
{
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
public void setMediaType(String mediaType)
|
||||
{
|
||||
this.mediaType = mediaType;
|
||||
}
|
||||
|
||||
public void setProperties(Map<String, String> properties)
|
||||
{
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public void addProperty(String predicate, String object)
|
||||
{
|
||||
this.properties.put(predicate, object);
|
||||
}
|
||||
}
|
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import org.apache.abdera.Abdera;
|
||||
import org.apache.abdera.model.Service;
|
||||
import org.apache.abdera.model.Workspace;
|
||||
|
||||
public class ServiceDocument
|
||||
{
|
||||
private String version = "2.0";
|
||||
private int maxUploadSize = -1;
|
||||
|
||||
private Service service;
|
||||
|
||||
public ServiceDocument()
|
||||
{
|
||||
Abdera abdera = new Abdera();
|
||||
this.service = abdera.newService();
|
||||
}
|
||||
|
||||
public Service getWrappedService()
|
||||
{
|
||||
return service;
|
||||
}
|
||||
|
||||
public Service getAbderaService()
|
||||
{
|
||||
// here is where we compress everything from SWORD into Abdera
|
||||
// and the output has to be a full clone, not by reference
|
||||
Service abderaService = (Service) this.service.clone();
|
||||
abderaService.addSimpleExtension(UriRegistry.SWORD_VERSION, this.version);
|
||||
if (maxUploadSize > -1)
|
||||
{
|
||||
abderaService.addSimpleExtension(UriRegistry.SWORD_MAX_UPLOAD_SIZE, Integer.toString(this.maxUploadSize));
|
||||
}
|
||||
return abderaService;
|
||||
}
|
||||
|
||||
public void setVersion(String version)
|
||||
{
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public void setMaxUploadSize(int maxUploadSize)
|
||||
{
|
||||
this.maxUploadSize = maxUploadSize;
|
||||
}
|
||||
|
||||
public void addWorkspace(SwordWorkspace workspace)
|
||||
{
|
||||
// FIXME: or do we just keep a reference of these until we get a call to getAbderaService()?
|
||||
Workspace abderaWorkspace = workspace.getAbderaWorkspace();
|
||||
this.service.addWorkspace(abderaWorkspace);
|
||||
}
|
||||
}
|
@@ -1,98 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import org.apache.abdera.model.Element;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ServiceDocumentAPI extends SwordAPIEndpoint
|
||||
{
|
||||
private static Logger log = Logger.getLogger(ServiceDocumentAPI.class);
|
||||
|
||||
protected ServiceDocumentManager sdm;
|
||||
|
||||
public ServiceDocumentAPI(ServiceDocumentManager sdm, SwordConfiguration config)
|
||||
{
|
||||
super(config);
|
||||
this.sdm = sdm;
|
||||
}
|
||||
|
||||
public void get(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
// do the initial authentication
|
||||
AuthCredentials auth = null;
|
||||
try
|
||||
{
|
||||
auth = this.getAuthCredentials(req);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
if (e.isRetry())
|
||||
{
|
||||
String s = "Basic realm=\"SWORD2\"";
|
||||
resp.setHeader("WWW-Authenticate", s);
|
||||
resp.setStatus(401);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
String sdUri = this.getFullUrl(req);
|
||||
|
||||
// delegate to the implementation to get the service document itself
|
||||
ServiceDocument serviceDocument = this.sdm.getServiceDocument(sdUri, auth, this.config);
|
||||
this.addGenerator(serviceDocument, this.config);
|
||||
|
||||
// set the content-type and write the service document to the output stream
|
||||
resp.setHeader("Content-Type", "application/atomserv+xml");
|
||||
serviceDocument.getAbderaService().writeTo(resp.getWriter());
|
||||
}
|
||||
catch (SwordError se)
|
||||
{
|
||||
// this is a SWORD level error, to be thrown to the client appropriately
|
||||
this.swordError(req, resp, se);
|
||||
}
|
||||
catch (SwordServerException e)
|
||||
{
|
||||
// this is something else, to be raised as an internal server error
|
||||
throw new ServletException(e);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
// authentication actually failed at the server end; not a SwordError, but
|
||||
// need to throw a 403 Forbidden
|
||||
resp.sendError(403);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// flush the output stream
|
||||
resp.getWriter().flush();
|
||||
}
|
||||
}
|
||||
|
||||
protected void addGenerator(ServiceDocument doc, SwordConfiguration config)
|
||||
{
|
||||
Element generator = this.getGenerator(this.config);
|
||||
if (generator != null)
|
||||
{
|
||||
doc.getWrappedService().addExtension(generator);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
public interface ServiceDocumentManager
|
||||
{
|
||||
ServiceDocument getServiceDocument(String sdUri, AuthCredentials auth, SwordConfiguration config) throws SwordError, SwordServerException, SwordAuthException;
|
||||
}
|
@@ -1,76 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class Statement
|
||||
{
|
||||
protected String contentType;
|
||||
protected List<OriginalDeposit> originalDeposits;
|
||||
protected Map<String, String> states;
|
||||
protected List<ResourcePart> resources;
|
||||
protected Date lastModified;
|
||||
|
||||
public abstract void writeTo(Writer out) throws IOException;
|
||||
|
||||
public String getContentType()
|
||||
{
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public void setOriginalDeposits(List<OriginalDeposit> originalDeposits)
|
||||
{
|
||||
this.originalDeposits = originalDeposits;
|
||||
}
|
||||
|
||||
public void addOriginalDeposit(OriginalDeposit originalDeposit)
|
||||
{
|
||||
this.originalDeposits.add(originalDeposit);
|
||||
}
|
||||
|
||||
public void setResources(List<ResourcePart> resources)
|
||||
{
|
||||
this.resources = resources;
|
||||
}
|
||||
|
||||
public void addResource(ResourcePart resource)
|
||||
{
|
||||
this.resources.add(resource);
|
||||
}
|
||||
|
||||
public void setStates(Map<String, String> states)
|
||||
{
|
||||
this.states = states;
|
||||
}
|
||||
|
||||
public void setState(String state, String description)
|
||||
{
|
||||
this.states.clear();
|
||||
this.states.put(state, description);
|
||||
}
|
||||
|
||||
public void addState(String state, String description)
|
||||
{
|
||||
this.states.put(state, description);
|
||||
}
|
||||
|
||||
public Date getLastModified()
|
||||
{
|
||||
return lastModified;
|
||||
}
|
||||
|
||||
public void setLastModified(Date lastModified)
|
||||
{
|
||||
this.lastModified = lastModified;
|
||||
}
|
||||
}
|
@@ -1,108 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
public class StatementAPI extends SwordAPIEndpoint
|
||||
{
|
||||
private static Logger log = Logger.getLogger(CollectionAPI.class);
|
||||
|
||||
private StatementManager sm;
|
||||
|
||||
public StatementAPI(StatementManager sm, SwordConfiguration config)
|
||||
{
|
||||
super(config);
|
||||
this.sm = sm;
|
||||
}
|
||||
|
||||
public void get(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
// do the initial authentication
|
||||
AuthCredentials auth = null;
|
||||
try
|
||||
{
|
||||
auth = this.getAuthCredentials(req);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
if (e.isRetry())
|
||||
{
|
||||
String s = "Basic realm=\"SWORD2\"";
|
||||
resp.setHeader("WWW-Authenticate", s);
|
||||
resp.setStatus(401);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// there may be some content negotiation going on
|
||||
Map<String, String> accept = this.getAcceptHeaders(req);
|
||||
String uri = this.getFullUrl(req);
|
||||
|
||||
Statement statement = this.sm.getStatement(uri, accept, auth, this.config);
|
||||
|
||||
// set the content type
|
||||
resp.setHeader("Content-Type", statement.getContentType());
|
||||
|
||||
// set the last modified header
|
||||
// like: Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
|
||||
Date lastModified = statement.getLastModified() != null ? statement.getLastModified() : new Date();
|
||||
resp.setHeader("Last-Modified", sdf.format(lastModified));
|
||||
|
||||
// to set the content-md5 header we need to write the output to
|
||||
// a string and checksum it
|
||||
StringWriter writer = new StringWriter();
|
||||
statement.writeTo(writer);
|
||||
|
||||
// write the content-md5 header
|
||||
String md5 = ChecksumUtils.generateMD5(writer.toString().getBytes());
|
||||
resp.setHeader("Content-MD5", md5);
|
||||
|
||||
resp.getWriter().append(writer.toString());
|
||||
resp.getWriter().flush();
|
||||
|
||||
}
|
||||
catch (SwordServerException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
catch (SwordError se)
|
||||
{
|
||||
this.swordError(req, resp, se);
|
||||
}
|
||||
catch (NoSuchAlgorithmException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
catch (SwordAuthException e)
|
||||
{
|
||||
// authentication actually failed at the server end; not a SwordError, but
|
||||
// need to throw a 403 Forbidden
|
||||
resp.sendError(403);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface StatementManager
|
||||
{
|
||||
Statement getStatement(String iri, Map<String, String> accept, AuthCredentials auth, SwordConfiguration config)
|
||||
throws SwordServerException, SwordError, SwordAuthException;
|
||||
}
|
@@ -1,547 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import org.apache.abdera.Abdera;
|
||||
import org.apache.abdera.model.Document;
|
||||
import org.apache.abdera.model.Element;
|
||||
import org.apache.abdera.model.Entry;
|
||||
import org.apache.abdera.parser.Parser;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.fileupload.FileItemFactory;
|
||||
import org.apache.commons.fileupload.FileUploadException;
|
||||
import org.apache.commons.fileupload.disk.DiskFileItem;
|
||||
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
||||
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.*;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class SwordAPIEndpoint
|
||||
{
|
||||
protected SwordConfiguration config;
|
||||
|
||||
private static Logger log = Logger.getLogger(SwordAPIEndpoint.class);
|
||||
|
||||
protected SwordAPIEndpoint(SwordConfiguration config)
|
||||
{
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
protected AuthCredentials getAuthCredentials(HttpServletRequest request)
|
||||
throws SwordAuthException
|
||||
{
|
||||
// is there an On-Behalf-Of header?
|
||||
String obo = request.getHeader("On-Behalf-Of");
|
||||
|
||||
// is authentication required
|
||||
String authType = this.config.getAuthType();
|
||||
boolean authRequired = "Basic".equals(authType);
|
||||
|
||||
// is the user authenticating?
|
||||
String authHeader = request.getHeader("Authorization");
|
||||
|
||||
// are we meant to authenticate, but haven't been given anything?
|
||||
if (authRequired && (authHeader == null || "".equals(authHeader)))
|
||||
{
|
||||
throw new SwordAuthException(true);
|
||||
}
|
||||
|
||||
// by this stage we are either meant to authenticate and have been given credentials or
|
||||
// we don't need to authenticate. Either way we just fill in the AuthCredentials
|
||||
String[] userPass = this.decodeAuthHeader(authHeader);
|
||||
|
||||
if (userPass == null)
|
||||
{
|
||||
log.debug("No Authentication Credentials supplied");
|
||||
return new AuthCredentials(null, null, obo);
|
||||
}
|
||||
|
||||
AuthCredentials auth = new AuthCredentials(userPass[0], userPass[1], obo);
|
||||
return auth;
|
||||
}
|
||||
|
||||
protected String[] decodeAuthHeader(String encodedHeader)
|
||||
throws SwordAuthException
|
||||
{
|
||||
// we have an authentication header, so parse it
|
||||
String[] authBits = encodedHeader.split(" ");
|
||||
|
||||
// Auth header doesn't have 2 parts (Basic, [base 64 username/password])?
|
||||
if (authBits.length != 2)
|
||||
{
|
||||
log.fatal("Malformed Authorization header");
|
||||
throw new SwordAuthException("Malformed Authorization header");
|
||||
}
|
||||
|
||||
// is this basic auth? if not, we don't support it
|
||||
if (!"Basic".equalsIgnoreCase(authBits[0].trim()))
|
||||
{
|
||||
log.warn("Authentication method not supported: " + authBits[0]);
|
||||
return null;
|
||||
}
|
||||
|
||||
// get the username and password out of the base64 encoded Basic auth string
|
||||
String unencodedCreds = new String(Base64.decodeBase64(authBits[1].trim().getBytes()));
|
||||
String[] userPass = unencodedCreds.split(":", 2);
|
||||
|
||||
// did we get a username and password?
|
||||
if (userPass.length != 2)
|
||||
{
|
||||
log.fatal("Malformed Authorization header; unable to determine username/password boundary");
|
||||
throw new SwordAuthException("Malformed Authorization header; unable to determine username/password boundary");
|
||||
}
|
||||
|
||||
return userPass;
|
||||
}
|
||||
|
||||
protected String getFullUrl(HttpServletRequest req)
|
||||
{
|
||||
String url = req.getRequestURL().toString();
|
||||
String q = req.getQueryString();
|
||||
if (q != null && !"".equals(q))
|
||||
{
|
||||
url += "?" + q;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
protected void storeAndCheckBinary(Deposit deposit, SwordConfiguration config)
|
||||
throws SwordServerException, SwordError
|
||||
{
|
||||
// we require an input stream for this to work
|
||||
if (deposit.getInputStream() == null)
|
||||
{
|
||||
throw new SwordServerException("Attempting to store and check deposit which has no input stream");
|
||||
}
|
||||
|
||||
if (!config.storeAndCheckBinary())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
String tempDirectory = config.getTempDirectory();
|
||||
if (tempDirectory == null)
|
||||
{
|
||||
throw new SwordServerException("Store and Check operation requested, but no tempDirectory specified in config");
|
||||
}
|
||||
|
||||
String filename = tempDirectory + File.separator + "SWORD-" + UUID.randomUUID().toString();
|
||||
|
||||
try
|
||||
{
|
||||
InputStream inputstream = deposit.getInputStream();
|
||||
OutputStream outputstream = new FileOutputStream(new File(filename));
|
||||
try
|
||||
{
|
||||
byte[] buf = new byte[1024];
|
||||
int len;
|
||||
while ((len = inputstream.read(buf)) > 0)
|
||||
{
|
||||
outputstream.write(buf, 0, len);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
inputstream.close();
|
||||
outputstream.close();
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new SwordServerException(e);
|
||||
}
|
||||
|
||||
// Check the size is OK
|
||||
File file = new File(filename);
|
||||
long fLength = file.length() / 1024; // in kilobytes
|
||||
if ((config.getMaxUploadSize() != -1) && (fLength > config.getMaxUploadSize()))
|
||||
{
|
||||
String msg = "The uploaded file exceeded the maximum file size this server will accept (the file is " +
|
||||
fLength + "kB but the server will only accept files as large as " +
|
||||
config.getMaxUploadSize() + "kB)";
|
||||
throw new SwordError(UriRegistry.ERROR_MAX_UPLOAD_SIZE_EXCEEDED, msg);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// get the things we might want to compare
|
||||
String receivedMD5 = ChecksumUtils.generateMD5(filename);
|
||||
log.debug("Received filechecksum: " + receivedMD5);
|
||||
String md5 = deposit.getMd5();
|
||||
log.debug("Received file checksum header: " + md5);
|
||||
|
||||
if ((md5 != null) && (!md5.equals(receivedMD5)))
|
||||
{
|
||||
log.debug("Bad MD5 for file. Aborting with appropriate error message");
|
||||
String msg = "The received MD5 checksum for the deposited file did not match the checksum sent by the deposit client";
|
||||
throw new SwordError(UriRegistry.ERROR_CHECKSUM_MISMATCH, msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the file to be deposited
|
||||
deposit.setFile(file);
|
||||
}
|
||||
log.debug("Package temporarily stored as: " + filename);
|
||||
}
|
||||
catch (NoSuchAlgorithmException e)
|
||||
{
|
||||
throw new SwordServerException(e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new SwordServerException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addDepositPropertiesFromMultipart(Deposit deposit, HttpServletRequest req)
|
||||
throws ServletException, IOException, SwordError
|
||||
{
|
||||
// Parse the request for files (using the fileupload commons library)
|
||||
List<DiskFileItem> items = this.getPartsFromRequest(req);
|
||||
for (DiskFileItem item : items)
|
||||
{
|
||||
// find out which part we are looking at
|
||||
String contentDisposition = item.getHeaders().getHeader("Content-Disposition");
|
||||
String name = this.getName(contentDisposition);
|
||||
|
||||
if ("atom".equals(name))
|
||||
{
|
||||
InputStream entryPart = item.getInputStream();
|
||||
Abdera abdera = new Abdera();
|
||||
Parser parser = abdera.getParser();
|
||||
Document<Entry> entryDoc = parser.parse(entryPart);
|
||||
Entry entry = entryDoc.getRoot();
|
||||
deposit.setEntry(entry);
|
||||
}
|
||||
else if ("payload".equals(name))
|
||||
{
|
||||
String md5 = item.getHeaders().getHeader("Content-MD5");
|
||||
String packaging = item.getHeaders().getHeader("Packaging");
|
||||
String filename = this.getFilename(contentDisposition);
|
||||
if (filename == null || "".equals(filename))
|
||||
{
|
||||
throw new SwordError(UriRegistry.ERROR_BAD_REQUEST, "Filename could not be extracted from Content-Disposition");
|
||||
}
|
||||
String ct = item.getContentType();
|
||||
String mimeType = "application/octet-stream";
|
||||
if (ct != null)
|
||||
{
|
||||
String[] bits = ct.split(";");
|
||||
mimeType = bits[0].trim();
|
||||
}
|
||||
InputStream mediaPart = item.getInputStream();
|
||||
|
||||
deposit.setFilename(filename);
|
||||
deposit.setInputStream(mediaPart);
|
||||
deposit.setMimeType(mimeType);
|
||||
deposit.setMd5(md5);
|
||||
deposit.setPackaging(packaging);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
this.storeAndCheckBinary(deposit, this.config);
|
||||
}
|
||||
catch (SwordServerException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected Element getGenerator(SwordConfiguration config)
|
||||
{
|
||||
String generatorUri = config.generator();
|
||||
String generatorVersion = config.generatorVersion();
|
||||
String adminEmail = config.administratorEmail();
|
||||
if (generatorUri != null && !"".equals(generatorUri))
|
||||
{
|
||||
Abdera abdera = new Abdera();
|
||||
Element generator = abdera.getFactory().newGenerator();
|
||||
generator.setAttributeValue("uri", generatorUri);
|
||||
if (generatorVersion != null)
|
||||
{
|
||||
generator.setAttributeValue("version", generatorVersion);
|
||||
}
|
||||
if (adminEmail != null && !"".equals(adminEmail))
|
||||
{
|
||||
generator.setText(adminEmail);
|
||||
}
|
||||
return generator;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void addDepositPropertiesFromEntry(Deposit deposit, HttpServletRequest req)
|
||||
throws IOException
|
||||
{
|
||||
InputStream entryPart = req.getInputStream();
|
||||
Abdera abdera = new Abdera();
|
||||
Parser parser = abdera.getParser();
|
||||
Document<Entry> entryDoc = parser.parse(entryPart);
|
||||
Entry entry = entryDoc.getRoot();
|
||||
deposit.setEntry(entry);
|
||||
}
|
||||
|
||||
protected void addDepositPropertiesFromBinary(Deposit deposit, HttpServletRequest req)
|
||||
throws ServletException, IOException, SwordError
|
||||
{
|
||||
String contentType = this.getContentType(req);
|
||||
String contentDisposition = req.getHeader("Content-Disposition");
|
||||
String md5 = req.getHeader("Content-MD5");
|
||||
String packaging = req.getHeader("Packaging");
|
||||
if (packaging == null || "".equals(packaging))
|
||||
{
|
||||
packaging = UriRegistry.PACKAGE_BINARY;
|
||||
}
|
||||
InputStream file = req.getInputStream();
|
||||
|
||||
// now let's interpret and deal with the headers that we have
|
||||
String filename = this.getFilename(contentDisposition);
|
||||
if (filename == null || "".equals(filename))
|
||||
{
|
||||
throw new SwordError(UriRegistry.ERROR_BAD_REQUEST, "Filename could not be extracted from Content-Disposition");
|
||||
}
|
||||
|
||||
deposit.setFilename(filename);
|
||||
deposit.setMd5(md5);
|
||||
deposit.setPackaging(packaging);
|
||||
deposit.setInputStream(file);
|
||||
deposit.setMimeType(contentType);
|
||||
|
||||
try
|
||||
{
|
||||
this.storeAndCheckBinary(deposit, this.config);
|
||||
}
|
||||
catch (SwordServerException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void swordError(HttpServletRequest req, HttpServletResponse resp, SwordError e)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.config.returnErrorBody())
|
||||
{
|
||||
ErrorDocument doc = new ErrorDocument(e.getErrorUri(), e.getStatus());
|
||||
resp.sendError(doc.getStatus());
|
||||
return;
|
||||
}
|
||||
|
||||
// treatment is either the default value in the ErrorDocument OR the error message if it exists
|
||||
String treatment = e.getMessage();
|
||||
|
||||
// verbose description is the stack trace if allowed, otherwise null
|
||||
String verbose = null;
|
||||
if (this.config.returnStackTraceInError())
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
e.printStackTrace(pw);
|
||||
verbose = sw.getBuffer().toString();
|
||||
}
|
||||
|
||||
ErrorDocument doc;
|
||||
if (treatment == null)
|
||||
{
|
||||
doc = new ErrorDocument(e.getErrorUri(), e.getStatus(), verbose);
|
||||
}
|
||||
else
|
||||
{
|
||||
doc = new ErrorDocument(e.getErrorUri(), e.getStatus(), treatment, verbose);
|
||||
}
|
||||
|
||||
// now write the response
|
||||
resp.setStatus(doc.getStatus());
|
||||
resp.setHeader("Content-Type", "text/xml");
|
||||
|
||||
doc.writeTo(resp.getWriter(), this.config);
|
||||
resp.getWriter().flush();
|
||||
}
|
||||
catch (SwordServerException sse)
|
||||
{
|
||||
throw new ServletException(sse);
|
||||
}
|
||||
}
|
||||
|
||||
protected String getFilename(String contentDisposition)
|
||||
{
|
||||
if (contentDisposition == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// content dispositon should be of the form
|
||||
//
|
||||
// Content-Disposition: attachment; filename="[filename]"
|
||||
// but may have other features too, so we need to pick it apart
|
||||
String token = "; filename=";
|
||||
int fnArg = contentDisposition.indexOf(token);
|
||||
String fromFilename = contentDisposition.substring(fnArg + token.length());
|
||||
int nextSemiColon = fromFilename.indexOf(";");
|
||||
if (nextSemiColon < 0)
|
||||
{
|
||||
// we already have the filename
|
||||
return fromFilename;
|
||||
}
|
||||
String filename = fromFilename.substring(0, nextSemiColon);
|
||||
if (filename.startsWith("\""))
|
||||
{
|
||||
filename = filename.substring(1);
|
||||
}
|
||||
if (filename.endsWith("\""))
|
||||
{
|
||||
filename = filename.substring(0, filename.length());
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
protected String getName(String contentDisposition)
|
||||
{
|
||||
// FIXME: this is the same code as above, but with a different token; generalise
|
||||
if (contentDisposition == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// content dispositon should be of the form
|
||||
//
|
||||
// Content-Disposition: attachment; filename="[filename]"
|
||||
// but may have other features too, so we need to pick it apart
|
||||
String token = "; name=";
|
||||
int nameArg = contentDisposition.indexOf(token);
|
||||
String fromName = contentDisposition.substring(nameArg + token.length());
|
||||
int nextSemiColon = fromName.indexOf(";");
|
||||
String name = fromName.substring(0, nextSemiColon);
|
||||
if (name.startsWith("\""))
|
||||
{
|
||||
name = name.substring(1);
|
||||
}
|
||||
if (name.endsWith("\""))
|
||||
{
|
||||
name = name.substring(0, name.length());
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
protected List<DiskFileItem> getPartsFromRequest(HttpServletRequest request)
|
||||
throws ServletException
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create a factory for disk-based file items
|
||||
FileItemFactory factory = new DiskFileItemFactory();
|
||||
|
||||
// Create a new file upload handler
|
||||
ServletFileUpload upload = new ServletFileUpload(factory);
|
||||
|
||||
// Parse the request
|
||||
List<DiskFileItem> items = upload.parseRequest(request);
|
||||
|
||||
return items;
|
||||
}
|
||||
catch (FileUploadException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected Map<String, String> getAcceptHeaders(HttpServletRequest req)
|
||||
{
|
||||
Map<String, String> acceptHeaders = new HashMap<String, String>();
|
||||
Enumeration headers = req.getHeaderNames();
|
||||
while (headers.hasMoreElements())
|
||||
{
|
||||
String header = (String) headers.nextElement();
|
||||
if (header.toLowerCase().startsWith("accept"))
|
||||
{
|
||||
acceptHeaders.put(header, req.getHeader(header));
|
||||
}
|
||||
}
|
||||
return acceptHeaders;
|
||||
}
|
||||
|
||||
protected void copyInputToOutput(InputStream in, OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
final int BUFFER_SIZE = 1024 * 4;
|
||||
final byte[] buffer = new byte[BUFFER_SIZE];
|
||||
|
||||
while (true)
|
||||
{
|
||||
final int count = in.read(buffer, 0, BUFFER_SIZE);
|
||||
|
||||
if (-1 == count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// write out those same bytes
|
||||
out.write(buffer, 0, count);
|
||||
}
|
||||
}
|
||||
|
||||
protected String getContentType(HttpServletRequest req)
|
||||
{
|
||||
String contentType = req.getHeader("Content-Type");
|
||||
if (contentType == null)
|
||||
{
|
||||
contentType = "application/octet-stream";
|
||||
}
|
||||
return contentType;
|
||||
}
|
||||
|
||||
protected boolean getInProgress(HttpServletRequest req)
|
||||
throws SwordError
|
||||
{
|
||||
String iph = req.getHeader("In-Progress");
|
||||
boolean inProgress = false; // default value
|
||||
if (iph != null)
|
||||
{
|
||||
// first of all validate that the value is "true" or "false"
|
||||
if (!"true".equals(iph.trim()) && !"false".equals(iph.trim()))
|
||||
{
|
||||
throw new SwordError(UriRegistry.ERROR_BAD_REQUEST, "The In-Progress header MUST be 'true' or 'false'");
|
||||
}
|
||||
inProgress = "true".equals(iph.trim());
|
||||
}
|
||||
return inProgress;
|
||||
}
|
||||
|
||||
protected boolean getMetadataRelevant(HttpServletRequest req)
|
||||
throws SwordError
|
||||
{
|
||||
String mdr = req.getHeader("Metadata-Relevant");
|
||||
boolean metadataRelevant = false; // default value
|
||||
if (mdr != null)
|
||||
{
|
||||
// first of all validate that the value is "true" or "false"
|
||||
if (!"true".equals(mdr.trim()) && !"false".equals(mdr.trim()))
|
||||
{
|
||||
throw new SwordError(UriRegistry.ERROR_BAD_REQUEST, "The In-Progress header MUST be 'true' or 'false'");
|
||||
}
|
||||
metadataRelevant = "true".equals(mdr.trim());
|
||||
}
|
||||
return metadataRelevant;
|
||||
}
|
||||
}
|
@@ -1,44 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
public class SwordAuthException extends Exception
|
||||
{
|
||||
private boolean retry = false;
|
||||
|
||||
public SwordAuthException()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public SwordAuthException(boolean retry)
|
||||
{
|
||||
super();
|
||||
this.retry = retry;
|
||||
}
|
||||
|
||||
public SwordAuthException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SwordAuthException(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public SwordAuthException(Throwable cause)
|
||||
{
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public boolean isRetry()
|
||||
{
|
||||
return retry;
|
||||
}
|
||||
}
|
@@ -1,345 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import org.apache.abdera.Abdera;
|
||||
import org.apache.abdera.i18n.iri.IRI;
|
||||
import org.apache.abdera.model.Collection;
|
||||
import org.apache.abdera.model.Element;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class SwordCollection
|
||||
{
|
||||
private Collection collection;
|
||||
private List<String> multipartAccept = new ArrayList<String>();
|
||||
private Abdera abdera;
|
||||
private String collectionPolicy = null;
|
||||
private boolean mediation = false;
|
||||
private String treatment = null;
|
||||
private List<String> acceptPackaging = new ArrayList<String>();
|
||||
private List<IRI> subServices = new ArrayList<IRI>();
|
||||
private String dcAbstract = null;
|
||||
|
||||
public SwordCollection()
|
||||
{
|
||||
this.abdera = new Abdera();
|
||||
this.collection = this.abdera.getFactory().newCollection();
|
||||
}
|
||||
|
||||
public Collection getWrappedCollection()
|
||||
{
|
||||
return this.collection;
|
||||
}
|
||||
|
||||
public Collection getAbderaCollection()
|
||||
{
|
||||
Collection abderaCollection = (Collection) this.collection.clone();
|
||||
|
||||
// FIXME: this is wrong; clients must be free to leave the accepts blank
|
||||
// // ensure that there is an accept field set
|
||||
// List<String> singlePartAccepts = this.getSinglepartAccept();
|
||||
// if (singlePartAccepts.size() == 0)
|
||||
// {
|
||||
// abderaCollection.addAccepts("*/*");
|
||||
// }
|
||||
//
|
||||
// // ensure that there is multipart accepts set
|
||||
// List<String> multipartAccepts = this.getMultipartAccept();
|
||||
// if (multipartAccepts.size() == 0 || this.multipartAccept.size() == 0)
|
||||
// {
|
||||
// this.multipartAccept.add("*/*");
|
||||
// }
|
||||
|
||||
// add the multipart accepts as elements
|
||||
for (String mpa : this.multipartAccept)
|
||||
{
|
||||
Element element = this.abdera.getFactory().newElement(UriRegistry.APP_ACCEPT);
|
||||
element.setAttributeValue("alternate", "multipart/related");
|
||||
element.setText(mpa);
|
||||
abderaCollection.addExtension(element);
|
||||
}
|
||||
|
||||
// add the collection Policy
|
||||
if (this.collectionPolicy != null)
|
||||
{
|
||||
abderaCollection.addSimpleExtension(UriRegistry.SWORD_COLLECTION_POLICY, this.collectionPolicy);
|
||||
}
|
||||
|
||||
// add the mediation
|
||||
abderaCollection.addSimpleExtension(UriRegistry.SWORD_MEDIATION, (this.mediation ? "true" : "false"));
|
||||
|
||||
// add the treatment
|
||||
if (this.treatment != null)
|
||||
{
|
||||
abderaCollection.addSimpleExtension(UriRegistry.SWORD_TREATMENT, this.treatment);
|
||||
}
|
||||
|
||||
// add the acceptPackaging
|
||||
for (String ap : this.acceptPackaging)
|
||||
{
|
||||
abderaCollection.addSimpleExtension(UriRegistry.SWORD_ACCEPT_PACKAGING, ap);
|
||||
}
|
||||
|
||||
// add the sub service document IRI
|
||||
for (IRI ss : this.subServices)
|
||||
{
|
||||
abderaCollection.addSimpleExtension(UriRegistry.SWORD_SERVICE, ss.toString());
|
||||
}
|
||||
|
||||
// add the abstract
|
||||
if (this.dcAbstract != null)
|
||||
{
|
||||
abderaCollection.addSimpleExtension(UriRegistry.DC_ABSTRACT, this.dcAbstract);
|
||||
}
|
||||
|
||||
return abderaCollection;
|
||||
}
|
||||
|
||||
public void setLocation(String href)
|
||||
{
|
||||
this.collection.setHref(href);
|
||||
}
|
||||
|
||||
public void setAbstract(String dcAbstract)
|
||||
{
|
||||
this.dcAbstract = dcAbstract;
|
||||
}
|
||||
|
||||
public List<IRI> getSubServices()
|
||||
{
|
||||
return subServices;
|
||||
}
|
||||
|
||||
public void setSubServices(List<IRI> subServices)
|
||||
{
|
||||
this.subServices = subServices;
|
||||
}
|
||||
|
||||
public void addSubService(IRI subService)
|
||||
{
|
||||
this.subServices.add(subService);
|
||||
}
|
||||
|
||||
public void setCollectionPolicy(String collectionPolicy)
|
||||
{
|
||||
this.collectionPolicy = collectionPolicy;
|
||||
}
|
||||
|
||||
public void setMediation(boolean mediation)
|
||||
{
|
||||
this.mediation = mediation;
|
||||
}
|
||||
|
||||
public void setTreatment(String treatment)
|
||||
{
|
||||
this.treatment = treatment;
|
||||
}
|
||||
|
||||
public void setAcceptPackaging(List<String> acceptPackaging)
|
||||
{
|
||||
this.acceptPackaging = acceptPackaging;
|
||||
}
|
||||
|
||||
public void addAcceptPackaging(String acceptPackaging)
|
||||
{
|
||||
this.acceptPackaging.add(acceptPackaging);
|
||||
}
|
||||
|
||||
public String getCollectionPolicy()
|
||||
{
|
||||
return collectionPolicy;
|
||||
}
|
||||
|
||||
public boolean isMediation()
|
||||
{
|
||||
return mediation;
|
||||
}
|
||||
|
||||
public String getTreatment()
|
||||
{
|
||||
return treatment;
|
||||
}
|
||||
|
||||
public List<String> getAcceptPackaging()
|
||||
{
|
||||
return acceptPackaging;
|
||||
}
|
||||
|
||||
public void setTitle(String title)
|
||||
{
|
||||
this.collection.setTitle(title);
|
||||
}
|
||||
|
||||
public void setHref(String href)
|
||||
{
|
||||
this.collection.setHref(href);
|
||||
}
|
||||
|
||||
public void setAccept(String... mediaRanges)
|
||||
{
|
||||
this.collection.setAccept(mediaRanges);
|
||||
}
|
||||
|
||||
public void setAcceptsEntry()
|
||||
{
|
||||
this.collection.setAcceptsEntry();
|
||||
}
|
||||
|
||||
public void setAcceptsNothing()
|
||||
{
|
||||
this.collection.setAcceptsNothing();
|
||||
}
|
||||
|
||||
public void addAccepts(String mediaRange)
|
||||
{
|
||||
this.collection.addAccepts(mediaRange);
|
||||
}
|
||||
|
||||
public void addAccepts(String... mediaRanges)
|
||||
{
|
||||
this.collection.addAccepts(mediaRanges);
|
||||
}
|
||||
|
||||
public void addAcceptsEntry()
|
||||
{
|
||||
this.collection.addAcceptsEntry();
|
||||
}
|
||||
|
||||
public void setMultipartAccept(String... mediaRanges)
|
||||
{
|
||||
List<String> mrs = Arrays.asList(mediaRanges);
|
||||
this.multipartAccept.clear();
|
||||
this.multipartAccept.addAll(mrs);
|
||||
}
|
||||
|
||||
public void addMultipartAccepts(String mediaRange)
|
||||
{
|
||||
this.multipartAccept.add(mediaRange);
|
||||
}
|
||||
|
||||
public void addMultipartAccepts(String... mediaRanges)
|
||||
{
|
||||
List<String> mrs = Arrays.asList(mediaRanges);
|
||||
this.multipartAccept.addAll(mrs);
|
||||
}
|
||||
|
||||
public List<String> getMultipartAccept()
|
||||
{
|
||||
List<String> accepts = new ArrayList<String>();
|
||||
List<Element> elements = this.collection.getElements();
|
||||
boolean noAccept = false;
|
||||
for (Element e : elements)
|
||||
{
|
||||
String multipartRelated = e.getAttributeValue("alternate");
|
||||
QName qn = e.getQName();
|
||||
if (qn.getLocalPart().equals("accept") &&
|
||||
qn.getNamespaceURI().equals(UriRegistry.APP_NAMESPACE) &&
|
||||
"multipart-related".equals(multipartRelated))
|
||||
{
|
||||
String content = e.getText();
|
||||
if (content == null || "".equals(content))
|
||||
{
|
||||
noAccept = true;
|
||||
}
|
||||
if (content != null && !"".equals(content) && !accepts.contains(content))
|
||||
{
|
||||
accepts.add(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if there are no accept values, and noAccept has not been triggered, then we add the
|
||||
// default accept type
|
||||
if (accepts.size() == 0 && !noAccept)
|
||||
{
|
||||
accepts.add("application/atom+xml;type=entry");
|
||||
}
|
||||
|
||||
// rationalise and return
|
||||
return this.rationaliseAccepts(accepts);
|
||||
}
|
||||
|
||||
public List<String> getSinglepartAccept()
|
||||
{
|
||||
List<String> accepts = new ArrayList<String>();
|
||||
List<Element> elements = this.collection.getElements();
|
||||
boolean noAccept = false;
|
||||
for (Element e : elements)
|
||||
{
|
||||
String multipartRelated = e.getAttributeValue("alternate");
|
||||
QName qn = e.getQName();
|
||||
if (qn.getLocalPart().equals("accept") &&
|
||||
qn.getNamespaceURI().equals(UriRegistry.APP_NAMESPACE) &&
|
||||
!"multipart-related".equals(multipartRelated))
|
||||
{
|
||||
String content = e.getText();
|
||||
if (content == null || "".equals(content))
|
||||
{
|
||||
noAccept = true;
|
||||
}
|
||||
if (content != null && !"".equals(content) && !accepts.contains(content))
|
||||
{
|
||||
accepts.add(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if there are no accept values, and noAccept has not been triggered, then we add the
|
||||
// default accept type
|
||||
if (accepts.size() == 0 && !noAccept)
|
||||
{
|
||||
accepts.add("application/atom+xml;type=entry");
|
||||
}
|
||||
|
||||
// rationalise and return
|
||||
return this.rationaliseAccepts(accepts);
|
||||
}
|
||||
|
||||
private List<String> rationaliseAccepts(List<String> accepts)
|
||||
{
|
||||
List<String> rational = new ArrayList<String>();
|
||||
|
||||
// first, if "*/*" is there, then we accept anything
|
||||
if (accepts.contains("*/*"))
|
||||
{
|
||||
rational.add("*/*");
|
||||
return rational;
|
||||
}
|
||||
|
||||
// now look to see if we have <x>/* and if so eliminate the unnecessary accepts
|
||||
List<String> wildcards = new ArrayList<String>();
|
||||
for (String a : accepts)
|
||||
{
|
||||
if (a.contains("/*"))
|
||||
{
|
||||
String wild = a.substring(0, a.indexOf("/"));
|
||||
wildcards.add(wild);
|
||||
if (!rational.contains(a))
|
||||
{
|
||||
rational.add(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (String a : accepts)
|
||||
{
|
||||
String type = a.substring(0, a.indexOf("/"));
|
||||
if (!wildcards.contains(type))
|
||||
{
|
||||
rational.add(a);
|
||||
}
|
||||
}
|
||||
|
||||
// by the time we get here we will have only unique and correctly wildcarded accept fields
|
||||
return rational;
|
||||
}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
public interface SwordConfiguration
|
||||
{
|
||||
boolean returnDepositReceipt();
|
||||
|
||||
boolean returnStackTraceInError();
|
||||
|
||||
boolean returnErrorBody();
|
||||
|
||||
String generator();
|
||||
|
||||
String generatorVersion();
|
||||
|
||||
String administratorEmail();
|
||||
|
||||
String getAuthType();
|
||||
|
||||
boolean storeAndCheckBinary();
|
||||
|
||||
String getTempDirectory();
|
||||
|
||||
int getMaxUploadSize();
|
||||
}
|
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
public class SwordConfigurationDefault implements SwordConfiguration
|
||||
{
|
||||
public boolean returnDepositReceipt()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean returnStackTraceInError()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean returnErrorBody()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public String generator()
|
||||
{
|
||||
return "http://www.swordapp.org/";
|
||||
}
|
||||
|
||||
public String generatorVersion()
|
||||
{
|
||||
return "2.0";
|
||||
}
|
||||
|
||||
public String administratorEmail()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getAuthType()
|
||||
{
|
||||
return "None";
|
||||
}
|
||||
|
||||
public boolean storeAndCheckBinary()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getTempDirectory()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getMaxUploadSize()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
@@ -1,86 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
|
||||
import org.apache.abdera.model.Element;
|
||||
import org.apache.abdera.model.Entry;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SwordEntry
|
||||
{
|
||||
public Entry entry;
|
||||
|
||||
public SwordEntry(Entry entry)
|
||||
{
|
||||
this.entry = entry;
|
||||
}
|
||||
|
||||
public String getTitle()
|
||||
{
|
||||
return this.entry.getTitle();
|
||||
}
|
||||
|
||||
public String getSummary()
|
||||
{
|
||||
return this.entry.getSummary();
|
||||
}
|
||||
|
||||
public Entry getEntry()
|
||||
{
|
||||
return this.entry;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
try
|
||||
{
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
this.entry.writeTo(baos);
|
||||
return baos.toString();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// put the code in for getting a dublin core record out
|
||||
public Map<String, List<String>> getDublinCore()
|
||||
{
|
||||
Map<String, List<String>> dc = new HashMap<String, List<String>>();
|
||||
List<Element> extensions = this.entry.getExtensions();
|
||||
for (Element element : extensions)
|
||||
{
|
||||
if (UriRegistry.DC_NAMESPACE.equals(element.getQName().getNamespaceURI()))
|
||||
{
|
||||
// we have a dublin core extension
|
||||
String field = element.getQName().getLocalPart();
|
||||
String value = element.getText();
|
||||
|
||||
if (dc.containsKey(field))
|
||||
{
|
||||
dc.get(field).add(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
ArrayList<String> values = new ArrayList<String>();
|
||||
values.add(value);
|
||||
dc.put(field, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dc;
|
||||
}
|
||||
}
|
@@ -1,84 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SwordError extends Exception
|
||||
{
|
||||
private String errorUri;
|
||||
private int status = -1;
|
||||
|
||||
public SwordError()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public SwordError(String errorUri)
|
||||
{
|
||||
super(errorUri);
|
||||
this.errorUri = errorUri;
|
||||
}
|
||||
|
||||
public SwordError(String errorUri, int status)
|
||||
{
|
||||
super(errorUri);
|
||||
this.errorUri = errorUri;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public SwordError(String errorUri, String message)
|
||||
{
|
||||
super(message);
|
||||
this.errorUri = errorUri;
|
||||
}
|
||||
|
||||
public SwordError(String errorUri, int status, String message)
|
||||
{
|
||||
super(message);
|
||||
this.errorUri = errorUri;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public SwordError(String errorUri, Throwable cause)
|
||||
{
|
||||
super(errorUri, cause);
|
||||
this.errorUri = errorUri;
|
||||
}
|
||||
|
||||
public SwordError(String errorUri, int status, Throwable cause)
|
||||
{
|
||||
super(errorUri, cause);
|
||||
this.errorUri = errorUri;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public SwordError(String errorUri, String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
this.errorUri = errorUri;
|
||||
}
|
||||
|
||||
public SwordError(String errorUri, int status, String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
this.errorUri = errorUri;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getErrorUri()
|
||||
{
|
||||
return errorUri;
|
||||
}
|
||||
|
||||
public int getStatus()
|
||||
{
|
||||
return status;
|
||||
}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
public class SwordServerException extends Exception
|
||||
{
|
||||
public SwordServerException()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public SwordServerException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SwordServerException(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public SwordServerException(Throwable cause)
|
||||
{
|
||||
super(cause);
|
||||
}
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import org.apache.abdera.Abdera;
|
||||
import org.apache.abdera.model.Collection;
|
||||
import org.apache.abdera.model.Text;
|
||||
import org.apache.abdera.model.Workspace;
|
||||
|
||||
public class SwordWorkspace
|
||||
{
|
||||
private Workspace workspace;
|
||||
|
||||
public SwordWorkspace()
|
||||
{
|
||||
Abdera abdera = new Abdera();
|
||||
this.workspace = abdera.getFactory().newWorkspace();
|
||||
}
|
||||
|
||||
public Workspace getWrappedWorkspace()
|
||||
{
|
||||
return workspace;
|
||||
}
|
||||
|
||||
public Workspace getAbderaWorkspace()
|
||||
{
|
||||
// at the moment, this doesn't need to clone anything
|
||||
return workspace;
|
||||
}
|
||||
|
||||
public void addCollection(SwordCollection collection)
|
||||
{
|
||||
// FIXME: or should collections be managed internally until getAbderaWorkspace is called
|
||||
Collection abderaCollection = collection.getAbderaCollection();
|
||||
this.workspace.addCollection(abderaCollection);
|
||||
}
|
||||
|
||||
public Text setTitle(String title)
|
||||
{
|
||||
return this.workspace.setTitle(title);
|
||||
}
|
||||
}
|
@@ -1,60 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
public class UriRegistry
|
||||
{
|
||||
// Namespaces
|
||||
public static String SWORD_TERMS_NAMESPACE = "http://purl.org/net/sword/terms/";
|
||||
public static String APP_NAMESPACE = "http://www.w3.org/2007/app";
|
||||
public static String DC_NAMESPACE = "http://purl.org/dc/terms/";
|
||||
public static String ORE_NAMESPACE = "http://www.openarchives.org/ore/terms/";
|
||||
public static String ATOM_NAMESPACE = "http://www.w3.org/2005/Atom";
|
||||
|
||||
// QNames for Extension Elements
|
||||
public static QName SWORD_VERSION = new QName(SWORD_TERMS_NAMESPACE, "version");
|
||||
public static QName SWORD_MAX_UPLOAD_SIZE = new QName(SWORD_TERMS_NAMESPACE, "maxUploadSize");
|
||||
public static QName SWORD_COLLECTION_POLICY = new QName(SWORD_TERMS_NAMESPACE, "collectionPolicy");
|
||||
public static QName SWORD_MEDIATION = new QName(SWORD_TERMS_NAMESPACE, "mediation");
|
||||
public static QName SWORD_TREATMENT = new QName(SWORD_TERMS_NAMESPACE, "treatment");
|
||||
public static QName SWORD_ACCEPT_PACKAGING = new QName(SWORD_TERMS_NAMESPACE, "acceptPackaging");
|
||||
public static QName SWORD_SERVICE = new QName(SWORD_TERMS_NAMESPACE, "service");
|
||||
public static QName SWORD_PACKAGING = new QName(SWORD_TERMS_NAMESPACE, "packaging");
|
||||
public static QName SWORD_VERBOSE_DESCRIPTION = new QName(SWORD_TERMS_NAMESPACE, "verboseDescription");
|
||||
public static QName APP_ACCEPT = new QName(APP_NAMESPACE, "accept");
|
||||
public static QName DC_ABSTRACT = new QName(DC_NAMESPACE, "abstract");
|
||||
|
||||
// URIs for the statement
|
||||
public static String SWORD_DEPOSITED_BY = SWORD_TERMS_NAMESPACE + "depositedBy";
|
||||
public static String SWORD_DEPOSITED_ON_BEHALF_OF = SWORD_TERMS_NAMESPACE + "depositedOnBehalfOf";
|
||||
public static String SWORD_DEPOSITED_ON = SWORD_TERMS_NAMESPACE + "depositedOn";
|
||||
public static String SWORD_ORIGINAL_DEPOSIT = SWORD_TERMS_NAMESPACE + "originalDeposit";
|
||||
public static String SWORD_STATE_DESCRIPTION = SWORD_TERMS_NAMESPACE + "stateDescription";
|
||||
public static String SWORD_STATE = SWORD_TERMS_NAMESPACE + "state";
|
||||
|
||||
// rel values
|
||||
public static String REL_STATEMENT = "http://purl.org/net/sword/terms/statement";
|
||||
public static String REL_SWORD_EDIT = "http://purl.org/net/sword/terms/add";
|
||||
public static String REL_ORIGINAL_DEPOSIT = "http://purl.org/net/sword/terms/originalDeposit";
|
||||
public static String REL_DERIVED_RESOURCE = "http://purl.org/net/sword/terms/derivedResource";
|
||||
|
||||
// Package Formats
|
||||
public static String PACKAGE_SIMPLE_ZIP = "http://purl.org/net/sword/package/SimpleZip";
|
||||
public static String PACKAGE_BINARY = "http://purl.org/net/sword/package/Binary";
|
||||
|
||||
// Error Codes
|
||||
public static String ERROR_BAD_REQUEST = "http://purl.org/net/sword/error/ErrorBadRequest";
|
||||
public static String ERROR_CONTENT = "http://purl.org/net/sword/error/ErrorContent";
|
||||
public static String ERROR_CHECKSUM_MISMATCH = "http://purl.org/net/sword/error/ErrorChecksumMismatch";
|
||||
public static String ERROR_TARGET_OWNER_UNKNOWN = "http://purl.org/net/sword/error/TargetOwnerUnknown";
|
||||
public static String ERROR_MEDIATION_NOT_ALLOWED = "http://purl.org/net/sword/error/MediationNotAllowed";
|
||||
public static String ERROR_METHOD_NOT_ALLOWED = "http://purl.org/net/sword/error/MethodNotAllowed";
|
||||
public static String ERROR_MAX_UPLOAD_SIZE_EXCEEDED = "http://purl.org/net/sword/error/MaxUploadSizeExceeded";
|
||||
}
|
@@ -1,57 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server.servlets;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.swordapp.server.CollectionAPI;
|
||||
import org.swordapp.server.CollectionDepositManager;
|
||||
import org.swordapp.server.CollectionListManager;
|
||||
import org.swordapp.server.SwordConfiguration;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
public class CollectionServletDefault extends SwordServlet
|
||||
{
|
||||
private static Logger log = Logger.getLogger(CollectionServletDefault.class);
|
||||
|
||||
protected CollectionListManager clm = null;
|
||||
protected CollectionDepositManager cdm;
|
||||
protected CollectionAPI api;
|
||||
|
||||
public void init() throws ServletException
|
||||
{
|
||||
super.init();
|
||||
|
||||
// load the collection list manager implementation
|
||||
Object possibleClm = this.loadImplClass("collection-list-impl", true); // allow null
|
||||
this.clm = possibleClm == null ? null : (CollectionListManager) possibleClm;
|
||||
|
||||
// load the deposit manager implementation
|
||||
this.cdm = (CollectionDepositManager) this.loadImplClass("collection-deposit-impl", false);
|
||||
|
||||
// load the API
|
||||
this.api = new CollectionAPI(this.clm, this.cdm, this.config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
this.api.get(req, resp);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
this.api.post(req, resp);
|
||||
}
|
||||
}
|
@@ -1,78 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server.servlets;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.swordapp.server.ContainerAPI;
|
||||
import org.swordapp.server.ContainerManager;
|
||||
import org.swordapp.server.StatementAPI;
|
||||
import org.swordapp.server.StatementManager;
|
||||
import org.swordapp.server.SwordConfiguration;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ContainerServletDefault extends SwordServlet
|
||||
{
|
||||
private static Logger log = Logger.getLogger(ContainerServletDefault.class);
|
||||
|
||||
private ContainerManager cm;
|
||||
private ContainerAPI api;
|
||||
private StatementManager sm;
|
||||
|
||||
public void init() throws ServletException
|
||||
{
|
||||
super.init();
|
||||
|
||||
// load the container manager implementation
|
||||
this.cm = (ContainerManager) this.loadImplClass("container-impl", false);
|
||||
|
||||
// load the container manager implementation
|
||||
this.sm = (StatementManager) this.loadImplClass("statement-impl", false);
|
||||
|
||||
// initialise the underlying servlet processor
|
||||
this.api = new ContainerAPI(this.cm, this.sm, this.config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
this.api.get(req, resp);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHead(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
this.api.head(req, resp);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPut(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
this.api.put(req, resp);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
this.api.post(req, resp);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
this.api.delete(req, resp);
|
||||
}
|
||||
}
|
@@ -1,72 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server.servlets;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.swordapp.server.MediaResourceAPI;
|
||||
import org.swordapp.server.MediaResourceManager;
|
||||
import org.swordapp.server.SwordConfiguration;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
public class MediaResourceServletDefault extends SwordServlet
|
||||
{
|
||||
private static Logger log = Logger.getLogger(MediaResourceServletDefault.class);
|
||||
|
||||
protected MediaResourceManager mrm;
|
||||
protected MediaResourceAPI api;
|
||||
|
||||
public void init() throws ServletException
|
||||
{
|
||||
super.init();
|
||||
|
||||
// load the Media Resource Manager
|
||||
this.mrm = (MediaResourceManager) this.loadImplClass("media-resource-impl", false);
|
||||
|
||||
// load the api
|
||||
this.api = new MediaResourceAPI(this.mrm, this.config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
this.api.get(req, resp);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHead(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
this.api.head(req, resp);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
this.api.post(req, resp);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPut(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
this.api.put(req, resp);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
this.api.delete(req, resp);
|
||||
}
|
||||
}
|
@@ -1,41 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server.servlets;
|
||||
|
||||
import org.swordapp.server.ServiceDocumentAPI;
|
||||
import org.swordapp.server.ServiceDocumentManager;
|
||||
import org.swordapp.server.SwordConfiguration;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ServiceDocumentServletDefault extends SwordServlet
|
||||
{
|
||||
protected ServiceDocumentManager sdm;
|
||||
protected ServiceDocumentAPI api;
|
||||
|
||||
public void init() throws ServletException
|
||||
{
|
||||
super.init();
|
||||
|
||||
// load the service document implementation
|
||||
this.sdm = (ServiceDocumentManager) this.loadImplClass("service-document-impl", false);
|
||||
|
||||
// load the api
|
||||
this.api = new ServiceDocumentAPI(this.sdm, this.config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
this.api.get(req, resp);
|
||||
}
|
||||
}
|
@@ -1,42 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server.servlets;
|
||||
|
||||
import org.swordapp.server.*;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
public class StatementServletDefault extends SwordServlet
|
||||
{
|
||||
private static Logger log = Logger.getLogger(StatementServletDefault.class);
|
||||
|
||||
private StatementManager sm;
|
||||
private StatementAPI statementApi;
|
||||
|
||||
public void init() throws ServletException
|
||||
{
|
||||
super.init();
|
||||
|
||||
// load the container manager implementation
|
||||
this.sm = (StatementManager) this.loadImplClass("statement-impl", false);
|
||||
|
||||
// initialise the underlying servlet processor
|
||||
this.statementApi = new StatementAPI(this.sm, this.config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
this.statementApi.get(req, resp);
|
||||
}
|
||||
}
|
@@ -1,78 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.swordapp.server.servlets;
|
||||
|
||||
import org.apache.abdera.Abdera;
|
||||
import org.apache.abdera.model.Document;
|
||||
import org.apache.abdera.model.Entry;
|
||||
import org.apache.abdera.parser.Parser;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.fileupload.FileItemFactory;
|
||||
import org.apache.commons.fileupload.FileUploadException;
|
||||
import org.apache.commons.fileupload.disk.DiskFileItem;
|
||||
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
||||
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.swordapp.server.*;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SwordServlet extends HttpServlet
|
||||
{
|
||||
private static Logger log = Logger.getLogger(SwordServlet.class);
|
||||
|
||||
protected SwordConfiguration config;
|
||||
|
||||
public void init() throws ServletException
|
||||
{
|
||||
// load the configuration implementation
|
||||
this.config = (SwordConfiguration) this.loadImplClass("config-impl", false);
|
||||
}
|
||||
|
||||
protected Object loadImplClass(String paramName, boolean allowNull)
|
||||
throws ServletException
|
||||
{
|
||||
String className = getServletContext().getInitParameter(paramName);
|
||||
if (className == null)
|
||||
{
|
||||
if (allowNull)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
log.fatal("'" + paramName + "' init parameter not set in Servlet context");
|
||||
throw new ServletException("'" + paramName + "' init parameter not set in Servlet context");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
Object obj = Class.forName(className).newInstance();
|
||||
log.info("Using " + className + " as '" + paramName + "'");
|
||||
return obj;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.fatal("Unable to instantiate class from '" + paramName + "': " + className);
|
||||
throw new ServletException("Unable to instantiate class from '" + paramName + "': " + className, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,140 +0,0 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!--
|
||||
|
||||
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/
|
||||
|
||||
-->
|
||||
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
|
||||
|
||||
<web-app>
|
||||
|
||||
<display-name>SWORD 2.0 Server - Example web.xml</display-name>
|
||||
|
||||
<!-- Configuration Information -->
|
||||
|
||||
<context-param>
|
||||
<param-name>service-document-impl</param-name>
|
||||
<param-value>org.swordapp.server.ServiceDocumentManagerImpl</param-value>
|
||||
<description>
|
||||
The ServiceDocumentManager server implementation class name
|
||||
</description>
|
||||
</context-param>
|
||||
|
||||
<!-- this can be omitted if the server does not wish to support listing collection contents -->
|
||||
<context-param>
|
||||
<param-name>collection-list-impl</param-name>
|
||||
<param-value>org.swordapp.server.CollectionListManagerImpl</param-value>
|
||||
<description>
|
||||
The CollectionListManager server implementation class name
|
||||
</description>
|
||||
</context-param>
|
||||
|
||||
<context-param>
|
||||
<param-name>collection-deposit-impl</param-name>
|
||||
<param-value>org.swordapp.server.CollectionDepositManagerImpl</param-value>
|
||||
<description>
|
||||
The CollectionDepositManager server implementation class name
|
||||
</description>
|
||||
</context-param>
|
||||
|
||||
<context-param>
|
||||
<param-name>media-resource-impl</param-name>
|
||||
<param-value>org.swordapp.server.MediaResourceManagerImpl</param-value>
|
||||
<description>
|
||||
The MediaResourceManager server implementation class name
|
||||
</description>
|
||||
</context-param>
|
||||
|
||||
<context-param>
|
||||
<param-name>container-impl</param-name>
|
||||
<param-value>org.swordapp.server.ContainerManagerImpl</param-value>
|
||||
<description>
|
||||
The ContainerManager server implementation class name
|
||||
</description>
|
||||
</context-param>
|
||||
|
||||
<context-param>
|
||||
<param-name>statement-impl</param-name>
|
||||
<param-value>org.swordapp.server.StatementManagerImpl</param-value>
|
||||
<description>
|
||||
The StatementManager server implementation class name
|
||||
</description>
|
||||
</context-param>
|
||||
|
||||
<!-- This option here is an actual implementation of the configuration class, which
|
||||
contains some default values -->
|
||||
<context-param>
|
||||
<param-name>config-impl</param-name>
|
||||
<param-value>org.swordapp.server.SwordConfigurationDefault</param-value>
|
||||
<description>
|
||||
The SwordConfiguration server implementation class name
|
||||
</description>
|
||||
</context-param>
|
||||
|
||||
<context-param>
|
||||
<param-name>authentication-method</param-name>
|
||||
<param-value>Basic</param-value>
|
||||
<description>
|
||||
The type of authentication used : [Basic|None]
|
||||
</description>
|
||||
</context-param>
|
||||
|
||||
|
||||
<!-- Servlets -->
|
||||
<servlet>
|
||||
<servlet-name>servicedocument</servlet-name>
|
||||
<servlet-class>org.swordapp.server.servlets.ServiceDocumentServletDefault</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>collection</servlet-name>
|
||||
<servlet-class>org.swordapp.server.servlets.CollectionServletDefault</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>mediaresource</servlet-name>
|
||||
<servlet-class>org.swordapp.server.servlets.MediaResourceServletDefault</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>container</servlet-name>
|
||||
<servlet-class>org.swordapp.server.servlets.ContainerServletDefault</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>statement</servlet-name>
|
||||
<servlet-class>org.swordapp.server.servlets.StatementServletDefault</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<!-- Servlet Mappings -->
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>servicedocument</servlet-name>
|
||||
<url-pattern>/servicedocument/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>collection</servlet-name>
|
||||
<url-pattern>/collection/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>mediaresource</servlet-name>
|
||||
<url-pattern>/edit-media/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>container</servlet-name>
|
||||
<url-pattern>/edit/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>statement</servlet-name>
|
||||
<url-pattern>/statement/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
</web-app>
|
@@ -1,164 +0,0 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-swordv2-webapp</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>DSpace SWORD v2 :: Web Application Resources</name>
|
||||
<description>DSpace SWORD v2 Deposit Service Provider Web Application Resources</description>
|
||||
<url>http://projects.dspace.org/dspace-sword-webapp</url>
|
||||
|
||||
<!--
|
||||
A Parent POM that Maven inherits DSpace Default
|
||||
POM atrributes from.
|
||||
-->
|
||||
<parent>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-swordv2</artifactId>
|
||||
<version>1.8.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<configuration>
|
||||
<archiveClasses>true</archiveClasses>
|
||||
<attachClasses>true</attachClasses>
|
||||
<!-- In version 2.1-alpha-1, this was incorrectly named warSourceExcludes -->
|
||||
<packagingExcludes>WEB-INF/lib/*.jar</packagingExcludes>
|
||||
<warSourceExcludes>WEB-INF/lib/*.jar</warSourceExcludes>
|
||||
<webResources>
|
||||
<resource>
|
||||
<filtering>true</filtering>
|
||||
<directory>${basedir}/src/main/webapp</directory>
|
||||
<includes>
|
||||
<include>WEB-INF/web.xml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</webResources>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>prepare-package</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<profiles>
|
||||
<!--
|
||||
when activated a dspace.config configuration
|
||||
file location passed on the commandline
|
||||
(-Ddspace.config=...) can be passed through
|
||||
to be used as a filter source by projects for
|
||||
tasks such as updating the ${dspace.dir} in
|
||||
web.xml etc.
|
||||
-->
|
||||
<profile>
|
||||
<activation>
|
||||
<property>
|
||||
<name>dspace.config</name>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<filters>
|
||||
<filter>${dspace.config}</filter>
|
||||
</filters>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>oracle-support</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>db.name</name>
|
||||
<value>oracle</value>
|
||||
</property>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.oracle</groupId>
|
||||
<artifactId>ojdbc6</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>postgres-support</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>!db.name</name>
|
||||
</property>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-swordv2-api</artifactId>
|
||||
<!--<version>1.8.0-SNAPSHOT</version>-->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.googlecode.foresite-toolkit</groupId>
|
||||
<artifactId>foresite</artifactId>
|
||||
<version>0.9</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.15</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>jmxtools</artifactId>
|
||||
<groupId>com.sun.jdmk</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>jms</artifactId>
|
||||
<groupId>javax.jms</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>jmxri</artifactId>
|
||||
<groupId>com.sun.jmx</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.abdera</groupId>
|
||||
<artifactId>abdera-client</artifactId>
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<!--
|
||||
The Subversion repository location is used by Continuum to update against
|
||||
when changes have occured, this spawns a new build cycle and releases snapshots
|
||||
into the snapshot repository below.
|
||||
-->
|
||||
<scm>
|
||||
<connection>scm:svn:http://scm.dspace.org/svn/repo/dspace/trunk/dspace-swordv2/dspace-swordv2-webapp</connection>
|
||||
<developerConnection>scm:svn:https://scm.dspace.org/svn/repo/dspace/trunk/dspace-swordv2/dspace-swordv2-webapp</developerConnection>
|
||||
<url>http://scm.dspace.org/svn/repo/dspace/trunk/dspace-swordv2/dspace-swordv2-webapp</url>
|
||||
</scm>
|
||||
|
||||
</project>
|
@@ -1,39 +1,170 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-swordv2</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>DSpace SWORD v2</name>
|
||||
<description>DSpace SWORD v2 Deposit Service Provider Web Application</description>
|
||||
<url>http://swordapp.org/</url>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-swordv2</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>DSpace SWORD v2 :: Web Application Resources</name>
|
||||
<description>DSpace SWORD v2 Deposit Service Provider Web Application</description>
|
||||
<url>http://projects.dspace.org/dspace-sword-webapp</url>
|
||||
|
||||
<!--
|
||||
A Parent POM that Maven inherits DSpace Default
|
||||
POM atrributes from.
|
||||
-->
|
||||
<parent>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-parent</artifactId>
|
||||
<version>1.8.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<!--
|
||||
A Parent POM that Maven inherits DSpace Default
|
||||
POM atrributes from.
|
||||
-->
|
||||
<parent>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-parent</artifactId>
|
||||
<version>1.8.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
<!--
|
||||
The Subversion repository location is used by Continuum to update against
|
||||
when changes have occurred, this spawns a new build cycle and releases snapshots
|
||||
into the snapshot repository below.
|
||||
-->
|
||||
<scm>
|
||||
<connection>scm:svn:http://scm.dspace.org/svn/repo/dspace/trunk/dspace-swordv2</connection>
|
||||
<developerConnection>scm:svn:https://scm.dspace.org/svn/repo/dspace/trunk/dspace-swordv2</developerConnection>
|
||||
<url>http://scm.dspace.org/svn/repo/dspace/trunk/dspace-swordv2</url>
|
||||
</scm>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<configuration>
|
||||
<archiveClasses>true</archiveClasses>
|
||||
<attachClasses>true</attachClasses>
|
||||
<!-- In version 2.1-alpha-1, this was incorrectly named warSourceExcludes -->
|
||||
<packagingExcludes>WEB-INF/lib/*.jar</packagingExcludes>
|
||||
<warSourceExcludes>WEB-INF/lib/*.jar</warSourceExcludes>
|
||||
<webResources>
|
||||
<resource>
|
||||
<filtering>true</filtering>
|
||||
<directory>${basedir}/src/main/webapp</directory>
|
||||
<includes>
|
||||
<include>WEB-INF/web.xml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</webResources>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>prepare-package</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
<!--
|
||||
The Subversion repository location is used by Continuum to update against
|
||||
when changes have occurred, this spawns a new build cycle and releases snapshots
|
||||
into the snapshot repository below.
|
||||
-->
|
||||
<scm>
|
||||
<connection>scm:svn:http://scm.dspace.org/svn/repo/dspace/trunk/dspace-swordv2</connection>
|
||||
<developerConnection>scm:svn:https://scm.dspace.org/svn/repo/dspace/trunk/dspace-swordv2</developerConnection>
|
||||
<url>http://scm.dspace.org/svn/repo/dspace/trunk/dspace-swordv2</url>
|
||||
</scm>
|
||||
<profiles>
|
||||
<!--
|
||||
when activated a dspace.config configuration
|
||||
file location passed on the commandline
|
||||
(-Ddspace.config=...) can be passed through
|
||||
to be used as a filter source by projects for
|
||||
tasks such as updating the ${dspace.dir} in
|
||||
web.xml etc.
|
||||
-->
|
||||
<profile>
|
||||
<activation>
|
||||
<property>
|
||||
<name>dspace.config</name>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<filters>
|
||||
<filter>${dspace.config}</filter>
|
||||
</filters>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>oracle-support</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>db.name</name>
|
||||
<value>oracle</value>
|
||||
</property>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.oracle</groupId>
|
||||
<artifactId>ojdbc6</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>postgres-support</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>!db.name</name>
|
||||
</property>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
|
||||
<modules>
|
||||
<module>dspace-swordv2-api</module>
|
||||
<module>dspace-swordv2-webapp</module>
|
||||
</modules>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.swordapp</groupId>
|
||||
<artifactId>server</artifactId>
|
||||
<version>2.0</version>
|
||||
<type>jar</type>
|
||||
<classifier>classes</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.swordapp</groupId>
|
||||
<artifactId>server</artifactId>
|
||||
<version>2.0</version>
|
||||
<type>war</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.googlecode.foresite-toolkit</groupId>
|
||||
<artifactId>foresite</artifactId>
|
||||
<version>0.9</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.15</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>jmxtools</artifactId>
|
||||
<groupId>com.sun.jdmk</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>jms</artifactId>
|
||||
<groupId>javax.jms</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>jmxri</artifactId>
|
||||
<groupId>com.sun.jmx</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.abdera</groupId>
|
||||
<artifactId>abdera-client</artifactId>
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
@@ -117,23 +117,17 @@
|
||||
<!-- DSpace Implementation of SWORDv2 Provider -->
|
||||
<dependency>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-swordv2-webapp</artifactId>
|
||||
<artifactId>dspace-swordv2</artifactId>
|
||||
<type>jar</type>
|
||||
<classifier>classes</classifier>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-swordv2-webapp</artifactId>
|
||||
<artifactId>dspace-swordv2</artifactId>
|
||||
<type>war</type>
|
||||
</dependency>
|
||||
|
||||
<!-- SWORD v2 API -->
|
||||
<dependency>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-swordv2-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-discovery-provider</artifactId>
|
||||
|
Reference in New Issue
Block a user