Skip to content

Commit

Permalink
Generalize suppression of PROTECTED properties
Browse files Browse the repository at this point in the history
- Add a test for those defined by mix:lockable
- Suppress version-related properties

Resolves: https://www.pivotaltracker.com/story/show/71266232
  • Loading branch information
mikedurbin authored and Andrew Woods committed May 18, 2014
1 parent 7ee52ec commit 77a2f6e
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 37 deletions.
Expand Up @@ -17,8 +17,7 @@

import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;
import com.hp.hpl.jena.graph.Node;
import com.hp.hpl.jena.graph.Triple;
import com.hp.hpl.jena.sparql.core.Quad;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.update.GraphStore;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
Expand All @@ -38,11 +37,11 @@
import org.slf4j.Logger;

import java.io.IOException;
import java.util.Iterator;

import static com.hp.hpl.jena.graph.Node.ANY;
import static com.hp.hpl.jena.graph.NodeFactory.createLiteral;
import static com.hp.hpl.jena.graph.NodeFactory.createURI;
import static com.hp.hpl.jena.rdf.model.ResourceFactory.createResource;
import static javax.ws.rs.core.MediaType.APPLICATION_XML;
import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
Expand All @@ -61,6 +60,8 @@
import static org.fcrepo.kernel.RdfLexicon.HAS_LOCK_TOKEN;
import static org.fcrepo.kernel.RdfLexicon.IS_DEEP;
import static org.fcrepo.kernel.RdfLexicon.LOCKS;
import static org.fcrepo.kernel.RdfLexicon.REPOSITORY_NAMESPACE;
import static org.junit.Assert.assertFalse;
import static org.slf4j.LoggerFactory.getLogger;

/**
Expand Down Expand Up @@ -341,6 +342,32 @@ public void testResponseContentTypes() throws Exception {
}
}

@Test
public void testOmissionOfJCRCLocksRDF() throws IOException {
final String pid = getRandomUniquePid();
createObject(pid);

final String lockToken = getLockToken(lockObject(pid));

final GraphStore rdf = getGraphStore(new HttpGet(serverAddress + pid));

final Resource subject = createResource(serverAddress + pid);
final String [] jcrLockTriples = new String[] {
REPOSITORY_NAMESPACE + "lockIsDeep",
REPOSITORY_NAMESPACE + "lockOwner" };

for (String prohibitedProperty : jcrLockTriples) {
assertFalse(prohibitedProperty + " must not appear in RDF for locked node!",
rdf.contains(
Node.ANY,
subject.asNode(),
createResource(prohibitedProperty).asNode(),
Node.ANY));
}

assertUnlockWithToken(pid, lockToken);
}

private void assertContentType(final HttpResponse response, final String contentType) throws IOException {
final Header[] contentTypes = response.getHeaders("Content-Type");
for (Header ctHeader : contentTypes) {
Expand Down
Expand Up @@ -27,6 +27,7 @@
import static org.fcrepo.kernel.RdfLexicon.HAS_PRIMARY_TYPE;
import static org.fcrepo.kernel.RdfLexicon.HAS_VERSION;
import static org.fcrepo.kernel.RdfLexicon.MIX_NAMESPACE;
import static org.fcrepo.kernel.RdfLexicon.REPOSITORY_NAMESPACE;
import static org.fcrepo.kernel.RdfLexicon.VERSIONING_POLICY;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
Expand Down Expand Up @@ -173,6 +174,7 @@ public void testCreateTwoVersionsWithSameLabel() throws Exception {
final GraphStore versionResults = getContent(serverAddress + objId + "/fcr:versions/label");

logger.debug("Got version profile:");
assertTrue("Should find a title.", versionResults.contains(Node.ANY, Node.ANY, DC_TITLE.asNode(), Node.ANY));
assertTrue("Should find the title from the last version tagged with the label \"label\"",
versionResults.contains(Node.ANY, Node.ANY, DC_TITLE.asNode(), NodeFactory.createLiteral("Second title")));
}
Expand Down Expand Up @@ -460,6 +462,31 @@ public void testGetVersionResponseContentTypes() throws Exception {
}
}

@Test
public void testOmissionOfJCRCVersionRDF() throws IOException {
final String pid = getRandomUniquePid();
createObject(pid);
addMixin(pid, MIX_NAMESPACE + "versionable");
final GraphStore rdf = getGraphStore(new HttpGet(serverAddress + pid));

final Resource subject = createResource(serverAddress + pid);
final String [] jcrVersioningTriples = new String[] {
REPOSITORY_NAMESPACE + "baseVersion",
REPOSITORY_NAMESPACE + "isCheckedOut",
REPOSITORY_NAMESPACE + "predecessors",
REPOSITORY_NAMESPACE + "versionHistory" };

for (String prohibitedProperty : jcrVersioningTriples) {
assertFalse(prohibitedProperty + " must not appear in RDF for version-enabled node!",
rdf.contains(
Node.ANY,
subject.asNode(),
createResource(prohibitedProperty).asNode(),
Node.ANY));
}

}

private void testDatastreamContentUpdatesCreateNewVersions(final String objName, final String dsName) throws IOException {
final String firstVersionText = "foo";
final String secondVersionText = "bar";
Expand Down
10 changes: 10 additions & 0 deletions fcrepo-kernel-api/src/main/java/org/fcrepo/jcr/FedoraJcrTypes.java
Expand Up @@ -54,4 +54,14 @@ public interface FedoraJcrTypes {
String FROZEN_NODE = "nt:frozenNode";

String FROZEN_MIXIN_TYPES = "jcr:frozenMixinTypes";

String JCR_UUID = "jcr:uuid";

String JCR_PRIMARY_TYPE = "jcr:primaryType";

String JCR_MIXIN_TYPES = "jcr:mixinTypes";

String [] EXPOSED_PROTECTED_JCR_TYPES
= new String[] { JCR_UUID, JCR_LASTMODIFIED, JCR_CREATED, JCR_CREATEDBY,
JCR_PRIMARY_TYPE, JCR_MIXIN_TYPES };
}
Expand Up @@ -113,12 +113,10 @@ private Iterator<Triple> triplesFromProperties(final javax.jcr.Node n)
throws RepositoryException {
LOGGER.trace("Creating triples for node: {}", n);
final UnmodifiableIterator<Property> nonBinaryProperties =
Iterators.filter(new PropertyIterator(n.getProperties()),
not(isInternalProperty));
Iterators.filter(new PropertyIterator(n.getProperties()), not(isInternalProperty));

final UnmodifiableIterator<Property> nonBinaryPropertiesCopy =
Iterators.filter(new PropertyIterator(n.getProperties()),
not(isInternalProperty));
Iterators.filter(new PropertyIterator(n.getProperties()), not(isInternalProperty));

return Iterators.concat(new ZippingIterator<>(
Iterators.transform(
Expand Down
Expand Up @@ -15,22 +15,16 @@
*/
package org.fcrepo.kernel.utils;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Throwables.propagate;
import static com.google.common.collect.Collections2.transform;
import static com.google.common.collect.ImmutableSet.copyOf;
import static com.google.common.collect.Iterators.contains;
import static com.google.common.collect.Iterators.forArray;
import static com.google.common.collect.Iterators.transform;
import static javax.jcr.PropertyType.BINARY;
import static org.modeshape.jcr.api.JcrConstants.JCR_DATA;
import static javax.jcr.PropertyType.REFERENCE;
import static javax.jcr.PropertyType.WEAKREFERENCE;
import static org.fcrepo.kernel.utils.NodePropertiesTools.REFERENCE_PROPERTY_SUFFIX;
import static org.slf4j.LoggerFactory.getLogger;

import java.util.Collection;
import java.util.Iterator;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterators;
import org.fcrepo.jcr.FedoraJcrTypes;
import org.fcrepo.kernel.services.functions.AnyTypesPredicate;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.slf4j.Logger;

import javax.jcr.Node;
import javax.jcr.Property;
Expand All @@ -42,18 +36,22 @@
import javax.jcr.nodetype.NodeTypeManager;
import javax.jcr.nodetype.PropertyDefinition;
import javax.jcr.version.VersionHistory;
import java.util.Collection;
import java.util.Iterator;

import org.fcrepo.jcr.FedoraJcrTypes;
import org.fcrepo.kernel.services.functions.AnyTypesPredicate;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.slf4j.Logger;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterators;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Throwables.propagate;
import static com.google.common.collect.Collections2.transform;
import static com.google.common.collect.ImmutableSet.copyOf;
import static com.google.common.collect.Iterators.contains;
import static com.google.common.collect.Iterators.forArray;
import static com.google.common.collect.Iterators.transform;
import static javax.jcr.PropertyType.BINARY;
import static javax.jcr.PropertyType.REFERENCE;
import static javax.jcr.PropertyType.WEAKREFERENCE;
import static org.fcrepo.kernel.utils.NodePropertiesTools.REFERENCE_PROPERTY_SUFFIX;
import static org.modeshape.jcr.api.JcrConstants.JCR_DATA;
import static org.slf4j.LoggerFactory.getLogger;

/**
* Convenience class with static methods for manipulating Fedora types in the
Expand Down Expand Up @@ -263,7 +261,41 @@ public boolean apply(final Property p) {

@Override
public boolean apply(final Property p) {
return isReferenceProperty.apply(p) || isBinaryContentProperty.apply(p);
return isReferenceProperty.apply(p) || isBinaryContentProperty.apply(p)
|| isProtectedAndShouldBeHidden.apply(p);
}
};

/**
* Check whether a property is protected (ie, cannot be modified directly) but
* is not one we've explicitly chosen to include.
*/
public static Predicate<Property> isProtectedAndShouldBeHidden =
new Predicate<Property>() {

@Override
public boolean apply(final Property p) {
try {
if (!p.getDefinition().isProtected()) {
return false;
} else if (p.getParent().isNodeType(FROZEN_NODE)) {
// everything on a frozen node is protected
// but we wish to display it anyway and there's
// another mechanism in place to make clear that
// things cannot be edited.
return false;
} else {
final String name = p.getName();
for (String exposedName : EXPOSED_PROTECTED_JCR_TYPES) {
if (name.equals(exposedName)) {
return false;
}
}
return true;
}
} catch (RepositoryException e) {
throw propagate(e);
}
}
};

Expand Down
Expand Up @@ -91,6 +91,7 @@
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.NodeTypeIterator;
import javax.jcr.nodetype.NodeTypeManager;
import javax.jcr.nodetype.PropertyDefinition;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import javax.jcr.query.QueryResult;
Expand All @@ -100,6 +101,7 @@
import javax.jcr.version.VersionIterator;
import javax.jcr.version.VersionManager;

import org.fcrepo.jcr.FedoraJcrTypes;
import org.fcrepo.kernel.RdfLexicon;
import org.fcrepo.kernel.rdf.HierarchyRdfContextOptions;
import org.fcrepo.kernel.rdf.IdentifierTranslator;
Expand All @@ -125,7 +127,7 @@
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.vocabulary.RDF;

public class JcrRdfToolsTest {
public class JcrRdfToolsTest implements FedoraJcrTypes {

private static final Logger LOGGER = getLogger(JcrRdfToolsTest.class);

Expand Down Expand Up @@ -178,6 +180,10 @@ private void buildMockNodeAndSurroundings() throws RepositoryException {
when(mockProperty.getName()).thenReturn(mockPredicateName);
when(mockProperty.getValue()).thenReturn(mockValue);
when(mockProperty.getType()).thenReturn(STRING);
when(mockProperty.getParent()).thenReturn(mockNode);
when(mockNode.isNodeType(FROZEN_NODE)).thenReturn(false);
when(mockProperty.getDefinition()).thenReturn(mockPropertyDefinition);
when(mockPropertyDefinition.isProtected()).thenReturn(false);
when(mockValue.getString()).thenReturn("abc");
when(mockParent.getProperties()).thenReturn(mockParentProperties);
when(mockParentProperties.hasNext()).thenReturn(false);
Expand Down Expand Up @@ -261,6 +267,28 @@ public final void shouldExcludeBinaryProperties() throws RepositoryException,
actual.contains(null, createProperty(mockPredicateName)));
}

@Test
public final void shouldExcludeSomeProtectedProperties() throws RepositoryException,
IOException {
when(mockNode.hasProperties()).thenReturn(true);
when(mockPropertyDefinition.isProtected()).thenReturn(true);
final Model actual = testObj.getJcrTriples(mockNode).asModel();
assertFalse("Found protected triple!", actual.contains(testSubjects.getSubject(mockNode.getPath()),
actual.getProperty(mockPredicateName), actual.createLiteral("abc")));
}

@Test
public final void shouldAllowSomeProtectedPropertiesForFrozenNodes() throws RepositoryException,
IOException {
when(mockNode.hasProperties()).thenReturn(true);
when(mockPropertyDefinition.isProtected()).thenReturn(true);
when(mockNode.isNodeType(FROZEN_NODE)).thenReturn(true);
final Model actual = testObj.getJcrTriples(mockNode).asModel();
assertTrue("Could not find protected triple!", actual.contains(testSubjects.getSubject(mockNode.getPath()),
actual.getProperty(mockPredicateName), actual.createLiteral("abc")));
}


@Test
public final void
shouldBeAbleToDisableResourceInlining() throws RepositoryException {
Expand Down Expand Up @@ -667,7 +695,10 @@ private static void logRDF(final Model rdf) throws IOException {
private NodeType mockNodeType;

@Mock
private javax.jcr.Property mockProperty, mockBinaryProperty;
private javax.jcr.Property mockProperty;

@Mock
private PropertyDefinition mockPropertyDefinition;

@Mock
private Value mockValue;
Expand Down

0 comments on commit 77a2f6e

Please sign in to comment.