Commits

Sam Adams committed df0f465

Add sword deposit support directly to collections

  • Participants
  • Parent commits 3d9983b

Comments (0)

Files changed (5)

File chempound-webapp/src/main/java/net/chempound/webapp/content/AggregationResource.java

 
     private final TripleStore tripleStore;
     private URI aggregationUri;
-    private final Injector injector;
+    private final Injector injector;    // TODO - use provider
 
     @Inject
     public AggregationResource(final TripleStore tripleStore, final Injector injector) {

File chempound-webapp/src/main/java/net/chempound/webapp/content/CollectionResource.java

+package net.chempound.webapp.content;
+
+import com.google.inject.Injector;
+import net.chempound.datastore.TripleStore;
+import net.chempound.webapp.sword.AbderaRepresentation;
+import org.apache.abdera.Abdera;
+import org.apache.abdera.i18n.iri.IRI;
+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.FileItemHeaders;
+import org.apache.commons.fileupload.FileItemIterator;
+import org.apache.commons.fileupload.FileItemStream;
+import org.apache.commons.fileupload.FileUploadException;
+import org.apache.commons.io.IOUtils;
+import org.restlet.data.Form;
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+import org.restlet.ext.fileupload.RestletFileUpload;
+import org.restlet.representation.EmptyRepresentation;
+import org.restlet.representation.Representation;
+import org.restlet.resource.Post;
+import org.swordapp.server.*;
+
+import javax.inject.Inject;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.restlet.data.MediaType.APPLICATION_ATOM;
+
+/**
+ * @author Sam Adams
+ */
+public class CollectionResource extends AggregationResource {
+
+    public static final MediaType APPLICATION_ATOM_FEED = MediaType.register(
+        "application/atom+xml;type=feed", "Atom feed document");
+
+    public static final MediaType APPLICATION_ATOM_ENTRY = MediaType.register(
+        "application/atom+xml;type=entry", "Atom entry document");
+
+    public static final MediaType MULTIPART_RELATED = MediaType.register(
+        "multipart/related", "Multipart related data");
+
+    private static final boolean IGNORE_CASE = true;
+
+    private final SwordConfiguration configuration;
+    private final CollectionDepositManager depositManager;
+
+    @Inject
+    public CollectionResource(final TripleStore tripleStore, final Injector injector,
+                              final SwordConfiguration configuration, final CollectionDepositManager depositManager) {
+        super(tripleStore, injector);
+
+        this.configuration = configuration;
+        this.depositManager = depositManager;
+    }
+
+    @Post("application/atom+xml|multipart/related|*/*")
+    public Representation handleDeposit(final Representation data) throws SwordError, SwordServerException, IOException, FileUploadException, SwordAuthException {
+
+//        if (data.getSize() == Representation.UNKNOWN_SIZE) {
+//            setStatus(Status.CLIENT_ERROR_LENGTH_REQUIRED);
+//            return null;
+//        }
+
+        final AuthCredentials auth = null;
+
+        final Deposit deposit = new Deposit();
+        deposit.setSlug(getSlug());
+        deposit.setInProgress(isInProgress());
+
+        getLogger().info("MIME type: " + data.getMediaType());
+
+        final MediaType mediaType = data.getMediaType();
+        if (mediaType != null && MULTIPART_RELATED.includes(mediaType)) {
+            getLogger().info("Performing multipart deposit");
+            handleMultipartDeposit(deposit);
+        }
+        else if (mediaType != null && APPLICATION_ATOM.includes(mediaType)) {
+            getLogger().info("Performing atom entry deposit");
+            handleAtomEntryDeposit(deposit);
+        }
+        else {
+            getLogger().info("Performing binary deposit");
+            handleBinaryDeposit(deposit);
+        }
+
+        getLogger().info("SWORD endpoint: " + getReference());
+
+        final DepositReceipt receipt = depositManager.createNew(getReference().toString(), deposit, auth, configuration);
+        final IRI editIRI = receipt.getEditIRI();
+        if (editIRI == null) {
+            throw new SwordServerException("No Edit-IRI found in Deposit Receipt; unable to send valid response");
+        }
+
+        setStatus(Status.SUCCESS_CREATED);
+        setLocationRef(editIRI.toString());
+        if (configuration.returnDepositReceipt()) {
+            return new AbderaRepresentation(receipt.getAbderaEntry(), APPLICATION_ATOM_ENTRY);
+        } else {
+            return new EmptyRepresentation();
+        }
+
+    }
+
+    private String getSlug() {
+        final Form headers = (Form) getRequestAttributes().get("org.restlet.http.headers");
+        return headers.getFirstValue("Slug", IGNORE_CASE);
+    }
+
+    protected boolean isInProgress() throws SwordError {
+        final Form headers = (Form) getRequestAttributes().get("org.restlet.http.headers");
+        final String iph = headers.getFirstValue("In-Progress", IGNORE_CASE);
+
+        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;
+    }
+
+
+    private void handleMultipartDeposit(final Deposit deposit) throws IOException, FileUploadException, SwordError {
+
+        final RestletFileUpload fileUpload = new RestletFileUpload();
+        final FileItemIterator itr = fileUpload.getItemIterator(getRequestEntity());
+
+        while (itr.hasNext()) {
+
+            final FileItemStream in = itr.next();
+            getLogger().info("Part: " + in.getFieldName() + " [" + in.getContentType() + "]");
+            if ("atom".equals(in.getFieldName())) {
+                getLogger().info("Reading atom entry");
+                final InputStream is = in.openStream();
+                Entry entry;
+                try {
+                    entry = readEntry(is);
+                } finally {
+                    is.close();
+                }
+                deposit.setEntry(entry);
+            }
+            else if ("payload".equals(in.getFieldName())) {
+                getLogger().info("Reading payload");
+
+                final MediaType contentType = getContentType();
+                final FileItemHeaders headers = in.getHeaders();
+                final String packaging = headers.getHeader("Packaging");
+                final String filename = in.getName();
+
+                getLogger().info("Received file [" + filename + "] [" + packaging + "] [" + contentType + "]");
+
+                final InputStream is = in.openStream();
+                try {
+                    byte[] b = IOUtils.toByteArray(is);
+                    // TODO - should check for 'Content-Transfer-Encoding: base64' header,
+                    // but that is not set by SWORD client right now...
+                    final String transferEncoding = headers.getHeader("Content-Transfer-Encoding");
+                    getLogger().info("Transfer encoding: " + transferEncoding);
+                    if (!"binary".equalsIgnoreCase(transferEncoding)) {
+                        final Base64 base64 = new Base64();
+                        b = base64.decode(b);
+                    }
+                    addPayload(deposit, contentType, packaging, filename, new ByteArrayInputStream(b));
+                } finally {
+                    is.close();
+                }
+            }
+            else {
+                throw new SwordError("Unknown part: " + in.getFieldName());
+            }
+        }
+    }
+
+    private void handleAtomEntryDeposit(final Deposit deposit) throws IOException {
+        final InputStream entryPart = getRequestEntity().getStream();
+        final Entry entry = readEntry(entryPart);
+        deposit.setEntry(entry);
+    }
+
+    private Entry readEntry(final InputStream entryPart) throws IOException {
+        final byte[] buffer = IOUtils.toByteArray(entryPart);
+
+        final Abdera abdera = new Abdera();
+        final Parser parser = abdera.getParser();
+        final Document<Entry> entryDoc = parser.parse(new ByteArrayInputStream(buffer));
+        return entryDoc.getRoot();
+    }
+
+    private void handleBinaryDeposit(final Deposit deposit) throws SwordError, IOException {
+        readPayload(deposit);
+    }
+
+    private void readPayload(final Deposit deposit) throws SwordError, IOException {
+        final MediaType contentType = getContentType();
+        final String packaging = getPackaging();
+
+        final String filename = getFilename();
+        if (filename == null || "".equals(filename)) {
+            throw new SwordError(UriRegistry.ERROR_BAD_REQUEST, "Filename could not be extracted from Content-Disposition header");
+        }
+
+        final InputStream file = getRequestEntity().getStream();
+
+        final byte[] md5 = getMd5();
+
+        addPayload(deposit, contentType, packaging, filename, file);
+    }
+
+    private void addPayload(final Deposit deposit, final MediaType contentType, final String packaging, final String filename, final InputStream inputStream) {
+        getLogger().info("Adding '" + filename + "' to deposit payload");
+        deposit.setFilename(filename);
+//        deposit.setMd5(md5);  TODO to hex
+        deposit.setPackaging(packaging);
+        deposit.setInputStream(inputStream);
+        deposit.setMimeType(contentType.toString());
+    }
+
+    private String getPackaging() {
+        final Form headers = (Form) getRequestAttributes().get("org.restlet.http.headers");
+        String packaging = headers.getFirstValue("Packaging", IGNORE_CASE);
+        if (packaging == null || "".equals(packaging)) {
+            packaging = UriRegistry.PACKAGE_BINARY;
+        }
+        return packaging;
+    }
+
+    private MediaType getContentType() {
+        MediaType contentType = getRequestEntity().getMediaType();
+        if (contentType == null) {
+            // TODO guess!
+            contentType = MediaType.APPLICATION_OCTET_STREAM;
+        }
+        return contentType;
+    }
+
+    private String getFilename() {
+        String filename = null;
+        if (getRequestEntity().getDisposition() != null) {
+            filename = getRequestEntity().getDisposition().getFilename();
+        } else {
+            final Form headers = (Form) getRequestAttributes().get("org.restlet.http.headers");
+            final String cd = headers.getFirstValue("Content-Disposition", IGNORE_CASE);
+            if (cd != null) {
+                final int i = cd.indexOf("filename=");
+                filename = cd.substring(i + 9);
+            }
+        }
+
+        return filename;
+    }
+
+    private byte[] getMd5() {
+        byte[] md5 = null;
+        if (getRequestEntity().getDigest() != null) {
+            if ("MD5".equals(getRequestEntity().getDigest().getAlgorithm())) {
+                md5 = getRequestEntity().getDigest().getValue();
+            }
+        }
+        return md5;
+    }
+
+}

File chempound-webapp/src/main/java/net/chempound/webapp/content/ContentRouter.java

 import com.hp.hpl.jena.rdf.model.Resource;
 import com.hp.hpl.jena.rdf.model.ResourceFactory;
 import net.chempound.datastore.TripleStore;
+import net.chempound.rdf.CPTerms;
 import net.chempound.rdf.ORE;
 import org.restlet.Context;
 import org.restlet.Request;
         final Reference ref = request.getResourceRef();
         final Resource resource = ResourceFactory.createResource(ref.toString());
 
+        if (isCollection(resource)) {
+            return injector.getInstance(CollectionResource.class);
+        }
         if (isAggregation(resource)) {
             return injector.getInstance(AggregationResource.class);
         }
         return null;
     }
 
+    private boolean isCollection(final Resource resource) {
+        return tripleStore.containsResourceOfType(resource, CPTerms.Collection);
+    }
+
     private boolean isAggregation(final Resource resource) {
         return tripleStore.containsResourceOfType(resource, ORE.Aggregation);
     }

File chempound-webapp/src/main/java/net/chempound/webapp/sword/CollectionResource.java

     public static final MediaType MULTIPART_RELATED = MediaType.register(
             "multipart/related", "Multipart related data");
 
-
     private static final boolean IGNORE_CASE = true;
 
-
     private final SwordConfiguration configuration;
     private final CollectionListManager listManager;
     private final CollectionDepositManager depositManager;

File chempound-webapp/src/main/resources/net/chempound/web/css/chempound.css

     border-style: outset;
     border-color: gray;
     background-color: white;
-    -moz-border-radius: ;
+    /*-moz-border-radius: ;*/
 }
 table.sparql-results td {
     border-width: 1px;
     border-style: outset;
     border-color: gray;
     background-color: white;
-    -moz-border-radius: ;
+    /*-moz-border-radius: ;*/
 }