Skip to content

Commit

Permalink
Merge pull request #549 from fcrepo4/prefer-server-managed
Browse files Browse the repository at this point in the history
Add a Preference for ServerManaged (and allow clients to exclude Server Managed properties on update)
  • Loading branch information
Andrew Woods committed Oct 18, 2014
2 parents 6cc2ad4 + 77f7769 commit 816ffa6
Show file tree
Hide file tree
Showing 19 changed files with 530 additions and 213 deletions.
Expand Up @@ -16,10 +16,10 @@
package org.fcrepo.http.api;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterators;
import com.hp.hpl.jena.graph.Triple;
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 org.apache.jena.riot.Lang;
import org.fcrepo.http.commons.api.rdf.HttpTripleUtil;
Expand All @@ -28,19 +28,23 @@
import org.fcrepo.http.commons.domain.Range;
import org.fcrepo.http.commons.domain.ldp.LdpPreferTag;
import org.fcrepo.http.commons.responses.RangeRequestInputStream;
import org.fcrepo.kernel.Datastream;
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.ManagedRdf;
import org.fcrepo.kernel.impl.rdf.impl.AclRdfContext;
import org.fcrepo.kernel.impl.rdf.impl.ChildrenRdfContext;
import org.fcrepo.kernel.impl.rdf.impl.ContainerRdfContext;
import org.fcrepo.kernel.impl.rdf.impl.ContentRdfContext;
import org.fcrepo.kernel.impl.rdf.impl.HashRdfContext;
import org.fcrepo.kernel.impl.rdf.impl.LdpContainerRdfContext;
import org.fcrepo.kernel.impl.rdf.impl.LdpIsMemberOfRdfContext;
import org.fcrepo.kernel.impl.rdf.impl.ParentRdfContext;
import org.fcrepo.kernel.impl.rdf.impl.PropertiesRdfContext;
import org.fcrepo.kernel.impl.rdf.impl.ReferencesRdfContext;
import org.fcrepo.kernel.impl.rdf.impl.RootRdfContext;
import org.fcrepo.kernel.impl.rdf.impl.TypeRdfContext;
import org.fcrepo.kernel.impl.services.TransactionServiceImpl;
import org.fcrepo.kernel.services.policy.StoragePolicyDecisionPoint;
Expand All @@ -62,7 +66,6 @@
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

import java.io.IOException;
import java.io.InputStream;
Expand All @@ -71,7 +74,10 @@
import java.util.Date;
import java.util.Iterator;

import static com.google.common.base.Predicates.alwaysTrue;
import static com.google.common.base.Predicates.not;
import static com.google.common.collect.Iterators.concat;
import static com.google.common.collect.Iterators.filter;
import static com.google.common.collect.Iterators.transform;
import static com.hp.hpl.jena.rdf.model.ModelFactory.createDefaultModel;
import static javax.ws.rs.core.HttpHeaders.CACHE_CONTROL;
Expand All @@ -82,6 +88,7 @@
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.RdfLexicon.isManagedNamespace;
import static org.slf4j.LoggerFactory.getLogger;

/**
Expand Down Expand Up @@ -157,34 +164,70 @@ public Triple apply(final Statement input) {
return Response.ok(rdfStream).build();
}

protected RdfStream getResourceTriples() {
return getResourceTriples(null);
}

protected RdfStream getResourceTriples(final Prefer prefer) {

final PreferTag returnPreference;

if (prefer != null && prefer.hasReturn()) {
returnPreference = prefer.getReturn();
} else if (prefer != null && prefer.hasHandling()) {
returnPreference = prefer.getHandling();
} else {
returnPreference = new PreferTag("");
returnPreference = PreferTag.emptyTag();
}

final LdpPreferTag ldpPreferences = new LdpPreferTag(returnPreference);

final RdfStream rdfStream = new RdfStream();

rdfStream.concat(getTriples(PropertiesRdfContext.class));
rdfStream.concat(getTriples(AclRdfContext.class));
rdfStream.concat(getTriples(TypeRdfContext.class));
final Predicate<Triple> tripleFilter;
if (ldpPreferences.prefersServerManaged()) {
tripleFilter = alwaysTrue();
} else {
tripleFilter = not(ManagedRdf.isManagedTriple);
}

rdfStream.concat(filter(getTriples(PropertiesRdfContext.class), tripleFilter));


if (ldpPreferences.prefersServerManaged()) {
rdfStream.concat(getTriples(TypeRdfContext.class));
} else {
rdfStream.concat(filter(getTriples(TypeRdfContext.class), new Predicate<Triple>() {
@Override
public boolean apply(final Triple input) {
return !isManagedNamespace.apply(input.getObject().getNameSpace());
}
}));
}


if (httpTripleUtil != null && ldpPreferences.prefersServerManaged()) {
httpTripleUtil.addHttpComponentModelsForResourceToStream(rdfStream, resource(), uriInfo, translator());
}

if (!returnPreference.getValue().equals("minimal")) {
final LdpPreferTag ldpPreferences = new LdpPreferTag(returnPreference);

if (ldpPreferences.prefersServerManaged()) {
rdfStream.concat(getTriples(AclRdfContext.class));
rdfStream.concat(getTriples(RootRdfContext.class));
rdfStream.concat(getTriples(ContentRdfContext.class));
}

rdfStream.concat(filter(getTriples(HashRdfContext.class), tripleFilter));

if (resource() instanceof Datastream) {
rdfStream.concat(filter(
getTriples(((Datastream) resource()).getBinary(), PropertiesRdfContext.class), tripleFilter));
}

if (ldpPreferences.prefersReferences()) {
rdfStream.concat(getTriples(ReferencesRdfContext.class));
}

rdfStream.concat(getTriples(ParentRdfContext.class));
if (ldpPreferences.prefersServerManaged()) {
rdfStream.concat(getTriples(ParentRdfContext.class));
}

if (ldpPreferences.prefersContainment()) {
rdfStream.concat(getTriples(ChildrenRdfContext.class));
Expand All @@ -199,23 +242,22 @@ protected RdfStream getResourceTriples(final Prefer prefer) {

final Iterator<FedoraResource> children = resource().getChildren();

rdfStream.concat(concat(transform(children,
rdfStream.concat(filter(concat(transform(children,
new Function<FedoraResource, RdfStream>() {

@Override
public RdfStream apply(final FedoraResource child) {
return child.getTriples(translator(), PropertiesRdfContext.class);
}
})));
})), tripleFilter));

}

rdfStream.concat(getTriples(ContainerRdfContext.class));
if (ldpPreferences.prefersServerManaged()) {
rdfStream.concat(getTriples(ContainerRdfContext.class));
}
}

addResponseInformationToStream(resource(), rdfStream, uriInfo,
translator());

return rdfStream;
}

Expand Down Expand Up @@ -342,16 +384,6 @@ protected FedoraResource resource() {
return resource;
}


protected void addResponseInformationToStream(
final FedoraResource resource, final RdfStream dataset,
final UriInfo uriInfo, final IdentifierConverter<Resource,FedoraResource> subjects) {
if (httpTripleUtil != null) {
httpTripleUtil.addHttpComponentModelsForResourceToStream(dataset, resource,
uriInfo, subjects);
}
}

/**
* Evaluate the cache control headers for the request to see if it can be served from
* the cache.
Expand Down Expand Up @@ -481,31 +513,19 @@ protected void replaceResourceBinaryWithStream(final FedoraBinary result,

protected void replaceResourceWithStream(final FedoraResource resource,
final InputStream requestBodyStream,
final MediaType contentType) {
final MediaType contentType,
final RdfStream resourceTriples) {
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 RdfStream resourceTriples;

if (resource.isNew()) {
resourceTriples = new RdfStream();
} else {
resourceTriples = getResourceTriples();
}

protected void patchResourcewithSparql(final FedoraResource resource,
final String requestBody,
final RdfStream resourceTriples) {
resource.updateProperties(translator(), requestBody, resourceTriples);
}

Expand Down
36 changes: 30 additions & 6 deletions fcrepo-http-api/src/main/java/org/fcrepo/http/api/FedoraLdp.java
Expand Up @@ -104,6 +104,7 @@ public class FedoraLdp extends ContentExposingResource {
private static final Logger LOGGER = getLogger(FedoraLdp.class);

@PathParam("path") protected String externalPath;
@HeaderParam("Prefer") protected Prefer prefer;

/**
* Default JAX-RS entry point
Expand Down Expand Up @@ -167,8 +168,7 @@ public Response options() {
@Produces({TURTLE + ";qs=10", JSON_LD + ";qs=8",
N3, N3_ALT2, RDF_XML, NTRIPLES, APPLICATION_XML, TEXT_PLAIN, TURTLE_X,
TEXT_HTML, APPLICATION_XHTML_XML, "*/*"})
public Response describe(@HeaderParam("Prefer") final Prefer prefer,
@HeaderParam("Range") final String rangeValue) throws IOException {
public Response describe(@HeaderParam("Range") final String rangeValue) throws IOException {
checkCacheControlHeaders(request, servletResponse, resource(), session);

addResourceHttpHeaders(resource());
Expand Down Expand Up @@ -241,13 +241,21 @@ public Response createOrReplaceObjectRdf(

evaluateRequestPreconditions(request, servletResponse, resource, session);

final RdfStream resourceTriples;

if (resource.isNew()) {
resourceTriples = new RdfStream();
} else {
resourceTriples = getResourceTriples(prefer);
}

if (requestBodyStream == null && !resource.isNew()) {
throw new ClientErrorException("No RDF provided and the resource already exists!", CONFLICT);
} else if (requestBodyStream != null) {
if ((resource instanceof FedoraObject || resource instanceof Datastream)
&& isRdfContentType(contentType.toString())) {
try {
replaceResourceWithStream(resource, requestBodyStream, contentType);
replaceResourceWithStream(resource, requestBodyStream, contentType, resourceTriples);
} catch (final RiotException e) {
throw new BadRequestException("RDF was not parsable", e);
}
Expand Down Expand Up @@ -299,7 +307,15 @@ public Response updateSparql(@ContentLocation final InputStream requestBodyStrea

evaluateRequestPreconditions(request, servletResponse, resource(), session);

patchResourcewithSparql(resource(), requestBody);
final RdfStream resourceTriples;

if (resource().isNew()) {
resourceTriples = new RdfStream();
} else {
resourceTriples = getResourceTriples(prefer);
}

patchResourcewithSparql(resource(), requestBody, resourceTriples);

try {
session.save();
Expand Down Expand Up @@ -358,14 +374,22 @@ public Response createObject(@QueryParam("mixin") final String mixin,
effectiveContentType,
newObjectPath, contentDisposition);

final RdfStream resourceTriples;

if (result.isNew()) {
resourceTriples = new RdfStream();
} else {
resourceTriples = getResourceTriples(prefer);
}

if (requestBodyStream == null) {
LOGGER.trace("No request body detected");
} else {
LOGGER.trace("Received createObject with a request body and content type \"{}\"", contentTypeString);

if ((result instanceof FedoraObject || result instanceof Datastream)
&& isRdfContentType(contentTypeString)) {
replaceResourceWithStream(result, requestBodyStream, contentType);
replaceResourceWithStream(result, requestBodyStream, contentType, resourceTriples);
} else if (result instanceof FedoraBinary) {
LOGGER.trace("Created a datastream and have a binary payload.");

Expand All @@ -374,7 +398,7 @@ && isRdfContentType(contentTypeString)) {

} else if (contentTypeString.equals(contentTypeSPARQLUpdate)) {
LOGGER.trace("Found SPARQL-Update content, applying..");
patchResourcewithSparql(result, IOUtils.toString(requestBodyStream));
patchResourcewithSparql(result, IOUtils.toString(requestBodyStream), resourceTriples);
} else {
if (requestBodyStream.read() != -1) {
throw new ClientErrorException("Invalid Content Type " + contentTypeString, UNSUPPORTED_MEDIA_TYPE);
Expand Down

0 comments on commit 816ffa6

Please sign in to comment.