Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Update LDP and Batch endpoints to use consistent write logic for crea…
…te +

updates
  • Loading branch information
cbeer committed Oct 9, 2014
1 parent 530b965 commit 4f36eaa
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 200 deletions.
Expand Up @@ -18,9 +18,13 @@
import com.google.common.base.Function;
import com.google.common.collect.Iterators;
import com.hp.hpl.jena.graph.Triple;
import com.hp.hpl.jena.query.Dataset;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import org.apache.commons.lang.StringUtils;
import org.apache.jena.riot.Lang;
import org.fcrepo.http.commons.api.rdf.HttpTripleUtil;
import org.fcrepo.http.commons.domain.Prefer;
Expand All @@ -30,6 +34,7 @@
import org.fcrepo.http.commons.responses.RangeRequestInputStream;
import org.fcrepo.kernel.FedoraBinary;
import org.fcrepo.kernel.FedoraResource;
import org.fcrepo.kernel.exception.InvalidChecksumException;
import org.fcrepo.kernel.exception.RepositoryRuntimeException;
import org.fcrepo.kernel.identifiers.IdentifierConverter;
import org.fcrepo.kernel.impl.rdf.impl.AclRdfContext;
Expand All @@ -54,6 +59,7 @@
import javax.jcr.Session;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.ForbiddenException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Context;
Expand All @@ -75,12 +81,13 @@
import static com.hp.hpl.jena.rdf.model.ModelFactory.createDefaultModel;
import static javax.ws.rs.core.HttpHeaders.CACHE_CONTROL;
import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
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.ok;
import static javax.ws.rs.core.Response.status;
import static org.apache.commons.lang.StringUtils.isBlank;
import static org.apache.jena.riot.RDFLanguages.contentTypeToLang;
import static org.fcrepo.kernel.rdf.GraphProperties.PROBLEMS_MODEL_NAME;
import static org.slf4j.LoggerFactory.getLogger;

/**
Expand Down Expand Up @@ -455,6 +462,88 @@ protected static MediaType getSimpleContentType(final MediaType requestContentTy
}

protected static boolean isRdfContentType(final String contentTypeString) {
return !contentTypeString.equals(TEXT_PLAIN) && contentTypeToLang(contentTypeString) != null;
return contentTypeToLang(contentTypeString) != null;
}

protected void replaceResourceBinaryWithStream(final FedoraBinary result,
final InputStream requestBodyStream,
final ContentDisposition contentDisposition,
final String contentTypeString,
final String checksum) throws InvalidChecksumException {
final URI checksumURI = checksumURI(checksum);
final String originalFileName = contentDisposition != null ? contentDisposition.getFileName() : "";

result.setContent(requestBodyStream,
contentTypeString,
checksumURI,
originalFileName,
datastreamService.getStoragePolicyDecisionPoint());
}

protected void replaceResourceWithStream(final FedoraResource resource,
final InputStream requestBodyStream,
final MediaType contentType) {
final Lang format = contentTypeToLang(contentType.toString());

final Model inputModel = createDefaultModel()
.read(requestBodyStream, getUri(resource).toString(), format.getName().toUpperCase());

final RdfStream resourceTriples;

if (resource.isNew()) {
resourceTriples = new RdfStream();
} else {
resourceTriples = getResourceTriples();
}
resource.replaceProperties(translator(), inputModel, resourceTriples);
}

protected void patchResourcewithSparql(final FedoraResource resource, final String requestBody) {
final Dataset properties = resource.updatePropertiesDataset(translator(), requestBody);

handleProblems(resource, properties);
}

/**
* Create a checksum URI object.
**/
private static URI checksumURI( final String checksum ) {
if (!isBlank(checksum)) {
return URI.create(checksum);
}
return null;
}

private void handleProblems(final FedoraResource resource, final Dataset properties) {

final Model problems = properties.getNamedModel(PROBLEMS_MODEL_NAME);

if (!problems.isEmpty()) {
LOGGER.info(
"Found these problems updating the properties for {}: {}", resource, problems);
final StringBuilder error = new StringBuilder();
final StmtIterator sit = problems.listStatements();
while (sit.hasNext()) {
final String message = getMessage(sit.next());
if (StringUtils.isNotEmpty(message) && error.indexOf(message) < 0) {
error.append(message + " \n");
}
}

throw new ForbiddenException(error.length() > 0 ? error.toString() : problems.toString());
}
}

/*
* Return the statement's predicate and its literal value if there's any
* @param stmt
* @return
*/
private static String getMessage(final Statement stmt) {

This comment has been minimized.

Copy link
@awoods

awoods Oct 12, 2014

This private method is not used. Please remove.

This comment has been minimized.

Copy link
@cbeer

cbeer Oct 13, 2014

Author Contributor

How do you figure? See 4f36eaa#diff-d372035f89c8d0846920e20bd13e0145R527.

Not that it matters, this whole chunk of logic is gone by the end.

This comment has been minimized.

Copy link
@awoods

awoods Oct 13, 2014

In my view of this PR, the method getMessage() still exists... although you removed handleProblems().

This comment has been minimized.

Copy link
@cbeer

cbeer Oct 13, 2014

Author Contributor

Ok, I'll remove it.

final Literal literal = stmt.getLiteral();
if (literal != null) {
return stmt.getPredicate().getURI() + ": " + literal.getString();
}
return null;
}
}
92 changes: 35 additions & 57 deletions fcrepo-http-api/src/main/java/org/fcrepo/http/api/FedoraBatch.java
Expand Up @@ -15,15 +15,14 @@
*/
package org.fcrepo.http.api;

import static com.hp.hpl.jena.rdf.model.ModelFactory.createDefaultModel;
import static java.nio.charset.StandardCharsets.UTF_8;
import static javax.ws.rs.core.MediaType.MULTIPART_FORM_DATA;
import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
import static javax.ws.rs.core.Response.noContent;
import static javax.ws.rs.core.Response.notAcceptable;
import static javax.ws.rs.core.Response.ok;
import static javax.ws.rs.core.Response.status;
import static javax.ws.rs.core.Response.Status;
import static org.apache.jena.riot.RDFLanguages.contentTypeToLang;
import static org.apache.jena.riot.WebContent.contentTypeSPARQLUpdate;
import static org.slf4j.LoggerFactory.getLogger;

Expand Down Expand Up @@ -61,23 +60,19 @@
import javax.ws.rs.core.Response.ResponseBuilder;

import com.google.common.annotations.VisibleForTesting;
import com.hp.hpl.jena.rdf.model.Model;

import org.apache.commons.io.IOUtils;
import org.apache.jena.riot.Lang;
import org.fcrepo.kernel.Datastream;
import org.fcrepo.kernel.FedoraBinary;
import org.fcrepo.kernel.FedoraObject;
import org.fcrepo.kernel.FedoraResource;
import org.fcrepo.kernel.exception.InvalidChecksumException;
import org.fcrepo.kernel.exception.RepositoryRuntimeException;
import org.fcrepo.kernel.utils.ContentDigest;
import org.fcrepo.kernel.utils.iterators.RdfStream;
import org.glassfish.jersey.media.multipart.BodyPart;
import org.glassfish.jersey.media.multipart.BodyPartEntity;
import org.glassfish.jersey.media.multipart.ContentDisposition;
import org.glassfish.jersey.media.multipart.MultiPart;
import org.modeshape.jcr.ExecutionContext;
import org.modeshape.jcr.value.PathFactory;
import org.slf4j.Logger;
import org.springframework.context.annotation.Scope;

Expand Down Expand Up @@ -174,10 +169,6 @@ public Response batchModify(final MultiPart multipart)

final String path = toPath(translator(), externalPath);

// TODO: this is ugly, but it works.
final PathFactory pathFactory = new ExecutionContext().getValueFactories().getPathFactory();
final org.modeshape.jcr.value.Path jcrPath = pathFactory.create(path);

try {

final Set<FedoraResource> resourcesChanged = new HashSet<>();
Expand Down Expand Up @@ -207,7 +198,7 @@ public Response batchModify(final MultiPart multipart)
if (contentDisposition.getFileName() != null) {
realContentDisposition = ATTACHMENT;
} else if (contentTypeString.equals(contentTypeSPARQLUpdate)
|| isRdfContentType(contentTypeString)) {
|| (isRdfContentType(contentTypeString) && !contentTypeString.equals(TEXT_PLAIN))) {
realContentDisposition = INLINE;
} else if (partName.equals(FORM_DATA_DELETE_PART_NAME)) {
realContentDisposition = DELETE;
Expand Down Expand Up @@ -244,33 +235,43 @@ public Response batchModify(final MultiPart multipart)
pathName = partName;
}

final String objPath = pathFactory.create(jcrPath, pathName).getCanonicalPath().getString();

switch (realContentDisposition) {
case INLINE:
final String absPath;

final FedoraResource resource = objectService.findOrCreateObject(session, objPath);
if (pathName.startsWith("/")) {
absPath = pathName;
} else {
absPath = path + "/" + pathName;
}
final String objPath = translator().asString(translator().toDomain(absPath));

if (contentTypeString.equals(contentTypeSPARQLUpdate)) {
resource.updatePropertiesDataset(translator(), IOUtils.toString(src));
} else if (contentTypeToLang(contentTypeString) != null) {
final Lang lang = contentTypeToLang(contentTypeString);
final FedoraResource resource;

final String format = lang.getName().toUpperCase();
if (nodeService.exists(session, objPath)) {
resource = getResourceFromPath(objPath);
} else if ((isRdfContentType(contentTypeString) && !contentTypeString.equals(TEXT_PLAIN)) ||
contentTypeString.equals(contentTypeSPARQLUpdate)) {
resource = objectService.findOrCreateObject(session, objPath);
} else {
resource = datastreamService.findOrCreateDatastream(session, objPath).getBinary();
}

final Model inputModel =
createDefaultModel().read(src,
translator().reverse().convert(resource.getNode()).toString(),
format);
final String checksum = contentDisposition.getParameters().get("checksum");

final RdfStream resourceTriples;
switch (realContentDisposition) {
case INLINE:
case ATTACHMENT:

if (resource.isNew()) {
resourceTriples = new RdfStream();
} else {
resourceTriples = getResourceTriples();
}
resource.replaceProperties(translator(), inputModel, resourceTriples);
if ((resource instanceof FedoraObject || resource instanceof Datastream)
&& isRdfContentType(contentTypeString)) {
replaceResourceWithStream(resource, src, part.getMediaType());
} else if (resource instanceof FedoraBinary) {
replaceResourceBinaryWithStream((FedoraBinary) resource,
src,
contentDisposition,
part.getMediaType().toString(),
checksum);
} else if (contentTypeString.equals(contentTypeSPARQLUpdate)) {
patchResourcewithSparql(resource, IOUtils.toString(src));
} else {
throw new WebApplicationException(notAcceptable(null)
.entity("Invalid Content Type " + contentTypeString).build());
Expand All @@ -280,31 +281,8 @@ public Response batchModify(final MultiPart multipart)

break;

case ATTACHMENT:

final URI checksumURI;

final String checksum = contentDisposition.getParameters().get("checksum");

if (checksum != null && !checksum.equals("")) {
checksumURI = new URI(checksum);
} else {
checksumURI = null;
}

final Datastream datastream = datastreamService.findOrCreateDatastream(session, objPath);

datastream.getBinary().setContent(src,
part.getMediaType().toString(),
checksumURI,
contentDisposition.getFileName(),
datastreamService.getStoragePolicyDecisionPoint());

resourcesChanged.add(datastream);
break;

case DELETE:
nodeService.getObject(session, objPath).delete();
resource.delete();
break;

default:
Expand Down

0 comments on commit 4f36eaa

Please sign in to comment.