Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #614 from fcrepo4/external-body
Use message/external-body MIME type for registering 'redirect' binaries
  • Loading branch information
Andrew Woods committed Oct 31, 2014
2 parents a5d74fc + f8a4cc8 commit 96c79ef
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 5 deletions.
Expand Up @@ -29,6 +29,7 @@
import static javax.ws.rs.core.Response.status;
import static javax.ws.rs.core.Response.Status.PARTIAL_CONTENT;
import static javax.ws.rs.core.Response.Status.REQUESTED_RANGE_NOT_SATISFIABLE;
import static javax.ws.rs.core.Response.temporaryRedirect;
import static org.apache.commons.lang.StringUtils.isBlank;
import static org.apache.jena.riot.RDFLanguages.contentTypeToLang;
import static org.fcrepo.jcr.FedoraJcrTypes.LDP_BASIC_CONTAINER;
Expand Down Expand Up @@ -119,6 +120,7 @@
public abstract class ContentExposingResource extends FedoraBaseResource {

private static final Logger LOGGER = getLogger(ContentExposingResource.class);
public static final MediaType MESSAGE_EXTERNAL_BODY = MediaType.valueOf("message/external-body");

@Context protected Request request;
@Context protected HttpServletResponse servletResponse;
Expand Down Expand Up @@ -166,7 +168,20 @@ public Triple apply(final Statement input) {
}
}));
} else {
return getBinaryContent(rangeValue);

final MediaType mediaType = MediaType.valueOf(contentTypeString);
if (MESSAGE_EXTERNAL_BODY.isCompatible(mediaType)
&& mediaType.getParameters().containsKey("access-type")
&& mediaType.getParameters().get("access-type").equals("URL")
&& mediaType.getParameters().containsKey("URL") ) {
try {
return temporaryRedirect(new URI(mediaType.getParameters().get("URL"))).build();
} catch (final URISyntaxException e) {
throw new RepositoryRuntimeException(e);
}
} else {
return getBinaryContent(rangeValue);
}
}

} else {
Expand Down Expand Up @@ -558,13 +573,14 @@ protected static boolean isRdfContentType(final String contentTypeString) {
protected void replaceResourceBinaryWithStream(final FedoraBinary result,
final InputStream requestBodyStream,
final ContentDisposition contentDisposition,
final String contentTypeString,
final MediaType contentType,
final String checksum) throws InvalidChecksumException {
final URI checksumURI = checksumURI(checksum);
final String originalFileName = contentDisposition != null ? contentDisposition.getFileName() : "";
final String originalContentType = contentType != null ? contentType.toString() : "";

result.setContent(requestBodyStream,
contentTypeString,
originalContentType,
checksumURI,
originalFileName,
storagePolicyDecisionPoint);
Expand Down
Expand Up @@ -265,7 +265,7 @@ public Response createOrReplaceObjectRdf(

if (resource instanceof FedoraBinary) {
replaceResourceBinaryWithStream((FedoraBinary) resource,
requestBodyStream, contentDisposition, contentType.toString(), checksum);
requestBodyStream, contentDisposition, requestContentType, checksum);
} else if (isRdfContentType(contentType.toString())) {
try {
replaceResourceWithStream(resource, requestBodyStream, contentType, resourceTriples);
Expand Down Expand Up @@ -417,7 +417,7 @@ && isRdfContentType(contentTypeString)) {
LOGGER.trace("Created a datastream and have a binary payload.");

replaceResourceBinaryWithStream((FedoraBinary) result,
requestBodyStream, contentDisposition, contentTypeString, checksum);
requestBodyStream, contentDisposition, requestContentType, checksum);

} else if (contentTypeString.equals(contentTypeSPARQLUpdate)) {
LOGGER.trace("Found SPARQL-Update content, applying..");
Expand Down
Expand Up @@ -19,13 +19,15 @@
import static com.google.common.collect.Iterables.any;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Lists.transform;

import static com.hp.hpl.jena.graph.NodeFactory.createURI;
import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
import static javax.ws.rs.core.MediaType.TEXT_PLAIN_TYPE;
import static javax.ws.rs.core.Response.Status.CREATED;
import static javax.ws.rs.core.Response.Status.NO_CONTENT;
import static javax.ws.rs.core.Response.Status.OK;
import static javax.ws.rs.core.Response.Status.TEMPORARY_REDIRECT;
import static org.apache.commons.io.IOUtils.toInputStream;
import static org.apache.jena.riot.WebContent.contentTypeSPARQLUpdate;
import static org.fcrepo.http.api.ContentExposingResource.getSimpleContentType;
Expand Down Expand Up @@ -56,6 +58,7 @@

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.text.ParseException;
import java.util.List;

Expand Down Expand Up @@ -559,6 +562,21 @@ public void testGetWithBinary() throws Exception {
assertTrue(IOUtils.toString((InputStream)actual.getEntity()).equals("xyz"));
}

@Test
public void testGetWithExternalMessageBinary() throws Exception {
final FedoraBinary mockResource = (FedoraBinary)setResource(FedoraBinary.class);
when(mockResource.getDescription()).thenReturn(mockNonRdfSourceDescription);
when(mockResource.getMimeType()).thenReturn("message/external-body; access-type=URL; URL=\"some:uri\"");
when(mockResource.getContent()).thenReturn(toInputStream("xyz"));
final Response actual = testObj.describe(null);
assertEquals(TEMPORARY_REDIRECT.getStatusCode(), actual.getStatus());
assertTrue("Should be an LDP NonRDFSource", mockResponse.getHeaders("Link").contains("<" + LDP_NAMESPACE +
"NonRDFSource>;rel=\"type\""));
assertTrue("Should contain a link to the binary description", mockResponse.getHeaders("Link").contains("<" +
idTranslator.toDomain(binaryDescriptionPath + "/fcr:metadata") + ">; rel=\"describedby\""));
assertEquals(new URI("some:uri"), actual.getLocation());
}

@Test
public void testGetWithBinaryDescription() throws Exception {
final NonRdfSourceDescription mockResource
Expand Down Expand Up @@ -782,6 +800,23 @@ public void testCreateNewBinary() throws Exception {
}
}

@Test
public void testCreateNewBinaryWithContentTypeWithParams() throws Exception {

setResource(Container.class);

when(mockBinaryService.findOrCreate(mockSession, "/b")).thenReturn(mockBinary);

try (final InputStream content = toInputStream("x")) {
final MediaType requestContentType = MediaType.valueOf("some/mime-type; with=some; param=s");
final Response actual = testObj.createObject(null, null, requestContentType, "b",
content);

assertEquals(CREATED.getStatusCode(), actual.getStatus());
verify(mockBinary).setContent(content, requestContentType.toString(), null, "", null);
}
}

@Test(expected = ClientErrorException.class)
public void testPostToBinary() throws Exception {
final FedoraBinary mockObject = (FedoraBinary)setResource(FedoraBinary.class);
Expand Down
Expand Up @@ -18,6 +18,7 @@
import static java.lang.Integer.MAX_VALUE;
import static java.lang.Integer.parseInt;
import static java.util.UUID.randomUUID;
import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
import static javax.ws.rs.core.Response.Status.CREATED;
import static javax.ws.rs.core.Response.Status.NO_CONTENT;
import static javax.ws.rs.core.Response.Status.OK;
Expand Down Expand Up @@ -132,6 +133,7 @@ protected static HttpPut putDSMethod(final String pid, final String ds,
new HttpPut(serverAddress + pid + "/" + ds);

put.setEntity(new StringEntity(content));
put.setHeader("Content-Type", TEXT_PLAIN);
return put;
}

Expand Down
Expand Up @@ -36,6 +36,7 @@
import static javax.ws.rs.core.Response.Status.NOT_MODIFIED;
import static javax.ws.rs.core.Response.Status.NO_CONTENT;
import static javax.ws.rs.core.Response.Status.OK;
import static javax.ws.rs.core.Response.Status.TEMPORARY_REDIRECT;
import static nu.validator.htmlparser.common.DoctypeExpectation.NO_DOCTYPE_ERRORS;
import static nu.validator.htmlparser.common.XmlViolationPolicy.ALLOW;
import static org.apache.http.impl.client.cache.CacheConfig.DEFAULT;
Expand Down Expand Up @@ -107,6 +108,7 @@
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
Expand All @@ -119,6 +121,7 @@
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.cache.CachingHttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.jena.riot.Lang;
Expand Down Expand Up @@ -2217,6 +2220,32 @@ public void testGraphShouldNotBeTooLumpy() throws Exception {

}

@Test
public void testExternalMessageBody() throws Exception {

// we need a client that won't automatically follow redirects
final HttpClient client = HttpClientBuilder.create().disableRedirectHandling().build();

final String pid = getRandomUniquePid();

final HttpPut httpPut = putObjMethod(pid);
httpPut.addHeader("Content-Type", "message/external-body; access-type=URL; " +
"URL=\"http://www.example.com/file\"");

final HttpResponse response = client.execute(httpPut);
final int status = response.getStatusLine().getStatusCode();
assertEquals("Didn't get a CREATED response!", CREATED.getStatusCode(), status);

final String subjectURI = response.getFirstHeader("Location").getValue();

final HttpGet get = new HttpGet(subjectURI);
final HttpResponse getResponse = client.execute(get);

LOGGER.error(EntityUtils.toString(getResponse.getEntity()));
assertEquals(TEMPORARY_REDIRECT.getStatusCode(), getResponse.getStatusLine().getStatusCode());
assertEquals("http://www.example.com/file", getResponse.getFirstHeader("Location").getValue());
}

private Date getDateFromModel(final Model model, final Resource subj, final Property pred) throws Exception {
final StmtIterator stmts = model.listStatements(subj, pred, (String) null);
if (stmts.hasNext()) {
Expand Down
Expand Up @@ -124,6 +124,30 @@ public void testDatastreamContent() throws IOException,

}

@Test
public void testDatastreamContentType() throws IOException,
RepositoryException,
InvalidChecksumException {
final Session session = repo.login();
containerService.findOrCreate(session, "/testDatastreamObject");

binaryService.findOrCreate(session, "/testDatastreamObject/testDatastreamNode1").setContent(
new ByteArrayInputStream("asdf".getBytes()),
"some/mime-type; with=params",
null,
null,
null
);

session.save();

final FedoraBinary ds = binaryService.findOrCreate(session,
"/testDatastreamObject/testDatastreamNode1");

assertEquals("some/mime-type; with=params", ds.getMimeType());

}

@Test
public void testDatastreamContentDigestAndLength() throws IOException,
RepositoryException,
Expand Down

0 comments on commit 96c79ef

Please sign in to comment.