/*
* Licensed to DuraSpace under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* DuraSpace licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.fcrepo.kernel.modeshape.rdf;
import static org.apache.jena.datatypes.xsd.XSDDatatype.XSDstring;
import static org.apache.jena.rdf.model.ModelFactory.createDefaultModel;
import static org.apache.jena.rdf.model.ResourceFactory.createPlainLiteral;
import static org.apache.jena.rdf.model.ResourceFactory.createProperty;
import static org.apache.jena.rdf.model.ResourceFactory.createResource;
import static org.apache.jena.rdf.model.ResourceFactory.createTypedLiteral;
import static javax.jcr.PropertyType.LONG;
import static javax.jcr.PropertyType.REFERENCE;
import static javax.jcr.PropertyType.STRING;
import static javax.jcr.PropertyType.URI;
import static javax.jcr.PropertyType.WEAKREFERENCE;
import static org.fcrepo.kernel.api.RdfLexicon.REPOSITORY_NAMESPACE;
import static org.fcrepo.kernel.modeshape.FedoraJcrConstants.FIELD_DELIMITER;
import static org.fcrepo.kernel.modeshape.FedoraJcrConstants.FROZEN_NODE;
import static org.fcrepo.kernel.modeshape.rdf.JcrRdfTools.getJcrNamespaceForRDFNamespace;
import static org.fcrepo.kernel.modeshape.rdf.JcrRdfTools.getRDFNamespaceForJcrNamespace;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import static org.modeshape.jcr.api.JcrConstants.NT_FOLDER;
import java.util.Collections;
import java.util.NoSuchElementException;
import java.util.UUID;
import java.util.function.Function;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.PropertyIterator;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
import javax.jcr.ValueFormatException;
import javax.jcr.Workspace;
import javax.jcr.nodetype.NodeDefinition;
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;
import javax.jcr.query.RowIterator;
import javax.jcr.version.Version;
import javax.jcr.version.VersionHistory;
import javax.jcr.version.VersionIterator;
import javax.jcr.version.VersionManager;
import org.fcrepo.kernel.api.FedoraTypes;
import org.fcrepo.kernel.api.utils.CacheEntry;
import org.fcrepo.kernel.modeshape.FedoraResourceImpl;
import org.fcrepo.kernel.modeshape.rdf.impl.DefaultIdentifierTranslator;
import org.fcrepo.kernel.modeshape.testutilities.TestPropertyIterator;
import org.fcrepo.kernel.modeshape.utils.FedoraTypesUtils;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.modeshape.jcr.api.JcrTools;
import org.modeshape.jcr.api.NamespaceRegistry;
import org.modeshape.jcr.value.BinaryValue;
import com.codahale.metrics.Counter;
import com.codahale.metrics.MetricRegistry;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.Property;
import org.apache.jena.rdf.model.RDFNode;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.rdf.model.Statement;
/**
* <p>JcrRdfToolsTest class.</p>
*
* @author awoods
* @author ajs6f
*/
public class JcrRdfToolsTest implements FedoraTypes {
private DefaultIdentifierTranslator testSubjects;
private JcrRdfTools testObj;
/*
* Also see enormous list of mock fields at bottom.
*/
@Before
public final void setUp() throws RepositoryException {
initMocks(this);
testSubjects = new DefaultIdentifierTranslator(mockSession);
buildMockNodeAndSurroundings();
testObj = new JcrRdfTools(testSubjects, mockSession);
}
private void buildMockNodeAndSurroundings() throws RepositoryException {
when(mockNode.getSession()).thenReturn(mockSession);
when(mockSession.getRepository()).thenReturn(mockRepository);
when(mockSession.getWorkspace()).thenReturn(mockWorkspace);
when(mockWorkspace.getNamespaceRegistry()).thenReturn(mockNsRegistry);
when(mockNsRegistry.isRegisteredUri("some:")).thenReturn(true);
when(mockNsRegistry.getPrefix("some:")).thenReturn("some");
when(mockSession.getRootNode()).thenReturn(mockRootNode);
when(mockParent.getPath()).thenReturn("/test");
when(mockParent.getPrimaryNodeType()).thenReturn(mockNodeType);
when(mockNode.getPath()).thenReturn("/test/jcr");
when(mockNode.getParent()).thenReturn(mockParent);
when(mockNode.getNodes()).thenReturn(mockNodes);
when(mockNodes.hasNext()).thenReturn(false);
when(mockNodes.next()).thenThrow(new NoSuchElementException());
when(mockNode.getPrimaryNodeType()).thenReturn(mockNodeType);
when(mockNode.getMixinNodeTypes()).thenReturn(
new NodeType[] {mockNodeType});
when(mockNodeType.getName()).thenReturn("jcr:someType");
when(mockNodeType.getChildNodeDefinitions()).thenReturn(
new NodeDefinition[] {mock(NodeDefinition.class)});
when(mockNode.getProperties()).thenReturn(
new TestPropertyIterator(mockProperty),
new TestPropertyIterator(mockProperty),
new TestPropertyIterator(mockProperty));
when(mockProperty.isMultiple()).thenReturn(false);
when(mockProperty.getParent()).thenReturn(mockNode);
when(mockProperty.getName()).thenReturn("some:property");
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);
when(mockNodeType.getSupertypes()).thenReturn(new NodeType[] {mockNodeType});
when(mockSession.getValueFactory()).thenReturn(mockValueFactory);
when(mockHashNode.getName()).thenReturn("#");
when(mockFedoraResource.getNode()).thenReturn(mockNode);
}
@Test
public final void shouldMapReferenceValuesToJcrPropertyValues()
throws RepositoryException {
final RDFNode n = testSubjects.toDomain("/abc");
// node references
when(mockSession.getNode("/abc")).thenReturn(mockNode);
when(mockSession.nodeExists("/abc")).thenReturn(true);
testObj.createValue(mockValueFactory, n, REFERENCE);
verify(mockValueFactory).createValue(mockNode, false);
testObj.createValue(mockValueFactory, n, WEAKREFERENCE);
verify(mockValueFactory).createValue(mockNode, true);
}
@Test
public final void shouldMapValuesIntoExistingIntoJcrPropertyTypes()
throws RepositoryException {
final RDFNode n = createTypedLiteral(0);
testObj.createValue(mockValueFactory, n, LONG);
verify(mockValueFactory).createValue("0", LONG);
final RDFNode resource = createResource("info:xyz");
testObj.createValue(mockValueFactory, resource, URI);
verify(mockValueFactory).createValue("info:xyz", URI);
}
@Test(expected = ValueFormatException.class)
public final void shouldMapRdfValuesToJcrPropertyValuesError()
throws RepositoryException {
// non-uri references - error
final RDFNode n = createResource();
testObj.createValue(mockValueFactory, n, REFERENCE);
}
@Test
public void shouldAddReferencePropertyForDomainObject() throws RepositoryException {
when(mockNodeType.getPropertyDefinitions()).thenReturn(new PropertyDefinition[]{});
when(mockNode.getMixinNodeTypes()).thenReturn(new NodeType[]{});
when(mockValueFactory.createValue(anyString(), eq(STRING))).thenReturn(mockValue);
when(mockValueFactory.createValue(mockNode, true)).thenReturn(mockReferenceValue);
when(mockSession.getNode("/x")).thenReturn(mockNode);
when(mockNode.setProperty(anyString(), any(Value[].class), anyInt())).thenReturn(mockProperty);
when(mockNode.getIdentifier()).thenReturn(UUID.randomUUID().toString());
testObj.addProperty(mockFedoraResource,
createProperty("some:property"),
testSubjects.toDomain("x"),
Collections.<String,String>emptyMap());
verify(mockNode).setProperty("some:property_ref", new Value[]{mockReferenceValue}, mockReferenceValue.getType
());
}
@Test
public void shouldNotAddReferencePropertyForNonDomainObject() throws RepositoryException {
when(mockNodeType.getPropertyDefinitions()).thenReturn(new PropertyDefinition[]{});
when(mockNode.getMixinNodeTypes()).thenReturn(new NodeType[]{});
when(mockValueFactory.createValue(anyString(), eq(STRING))).thenReturn(mockValue);
when(mockValueFactory.createValue(mockNode, true)).thenReturn(mockReferenceValue);
when(mockSession.getNode("/x")).thenReturn(mockNode);
when(mockNode.setProperty(anyString(), any(Value[].class), anyInt())).thenReturn(mockProperty);
testObj.addProperty(mockFedoraResource,
createProperty("some:property"),
createResource("some:resource"),
Collections.<String,String>emptyMap());
verify(mockNode, never()).setProperty(eq("some:property_ref"), any(Value[].class), anyInt());
}
@Test
public void testCreateValueForNode() throws RepositoryException {
when(mockNode.getSession().getValueFactory()).thenReturn(mockValueFactory);
when(mockNode.getPrimaryNodeType()).thenReturn(mockNodeType);
when(mockNodeType.getPropertyDefinitions()).thenReturn(new PropertyDefinition[]{});
when(mockNode.getMixinNodeTypes()).thenReturn(new NodeType[]{});
when(mockValueFactory.createValue(anyString(), eq(STRING))).thenReturn(mockValue);
final RDFNode n = createPlainLiteral("x");
testObj.createValue(mockNode, n, "some:property");
verify(mockValueFactory).createValue("x" + FIELD_DELIMITER + XSDstring.getURI(), STRING);
}
@Test
public final void shouldMapInternalJcrNamespaceToFcrepoNamespace() {
assertEquals(REPOSITORY_NAMESPACE,
getRDFNamespaceForJcrNamespace("http://www.jcp.org/jcr/1.0"));
}
@Test
public final void shouldMapFcrepoNamespaceToJcrNamespace() {
assertEquals("http://www.jcp.org/jcr/1.0",
getJcrNamespaceForRDFNamespace(REPOSITORY_NAMESPACE));
}
@Test
public final void shouldPassThroughOtherNamespaceValues() {
assertEquals("some-namespace-uri",
getJcrNamespaceForRDFNamespace("some-namespace-uri"));
assertEquals("some-namespace-uri",
getRDFNamespaceForJcrNamespace("some-namespace-uri"));
}
@Test
public void shouldPassthroughValidStatements() throws RepositoryException {
final Model m = createDefaultModel();
final Statement x = m.createStatement(testSubjects.toDomain("/"),
createProperty("info:x"),
createPlainLiteral("x"));
final Statement statement = testObj.skolemize(testSubjects, x, "info:fedora/");
assertEquals(x, statement);
}
@Test
public void shouldSkolemizeBlankNodeSubjects() throws RepositoryException {
final Model m = createDefaultModel();
final Resource resource = createResource();
final Statement x = m.createStatement(resource,
createProperty("info:x"),
testSubjects.toDomain("/"));
testObj.jcrTools = mock(JcrTools.class);
when(testObj.jcrTools.findOrCreateNode(eq(mockSession), anyString(), eq(NT_FOLDER))).thenReturn(mockNode);
when(mockNode.getPath()).thenReturn("/#/x");
when(mockNode.getParent()).thenReturn(mockHashNode);
when(mockHashNode.getParent()).thenReturn(mockChildNode);
when(mockHashNode.isNew()).thenReturn(true);
when(FedoraTypesUtils.getClosestExistingAncestor(mockSession, anyString())).thenReturn(mockHashNode);
final Statement statement = testObj.skolemize(testSubjects, x, "info:fedora/");
assertTrue("Doesn't match: " + statement.getSubject().toString(),
statement.getSubject().toString().startsWith("info:fedora/#"));
verify(mockNode).addMixin(FEDORA_RESOURCE);
}
@Test
public void shouldSkolemizeBlankNodeObjects() throws RepositoryException {
final Model m = createDefaultModel();
final Statement x = m.createStatement(testSubjects.toDomain("/foo"),
createProperty("info:x"),
createResource());
testObj.jcrTools = mock(JcrTools.class);
when(testObj.jcrTools.findOrCreateNode(eq(mockSession), anyString(), eq(NT_FOLDER))).thenReturn(mockNode);
when(mockNode.getPath()).thenReturn("/foo#abc");
when(mockNode.getParent()).thenReturn(mockHashNode);
when(mockHashNode.getParent()).thenReturn(mockChildNode);
when(mockHashNode.isNew()).thenReturn(true);
when(FedoraTypesUtils.getClosestExistingAncestor(mockSession, anyString())).thenReturn(mockHashNode);
final Statement statement = testObj.skolemize(testSubjects, x, x.getSubject().toString());
assertTrue(statement.getObject().toString().startsWith("info:fedora/foo#"));
verify(mockNode).addMixin(FEDORA_RESOURCE);
verify(mockNode.getParent()).addMixin(FEDORA_PAIRTREE);
}
@Test
public void shouldSkolemizeBlankNodeSubjectsAndObjects() throws RepositoryException {
final Model m = createDefaultModel();
final Resource resource = createResource();
final Statement x = m.createStatement(resource,
createProperty("info:x"),
resource);
testObj.jcrTools = mock(JcrTools.class);
when(testObj.jcrTools.findOrCreateNode(eq(mockSession), anyString(), eq(NT_FOLDER))).thenReturn(mockNode);
when(mockNode.getPath()).thenReturn("/#/x");
when(mockNode.getParent()).thenReturn(mockHashNode);
when(mockHashNode.getParent()).thenReturn(mockChildNode);
when(FedoraTypesUtils.getClosestExistingAncestor(mockSession, anyString())).thenReturn(mockHashNode);
final Statement statement = testObj.skolemize(testSubjects, x, "info:fedora/");
assertTrue(statement.getSubject().toString().startsWith("info:fedora/#"));
assertTrue(statement.getObject().toString().startsWith("info:fedora/#"));
}
@Test
public void shouldCreateHashUriSubjects() throws RepositoryException {
final Model m = createDefaultModel();
final Statement x = m.createStatement(testSubjects.toDomain("/some/#/abc"),
createProperty("info:x"),
testSubjects.toDomain("/"));
testObj.jcrTools = mock(JcrTools.class);
when(mockNode.getParent()).thenReturn(mockHashNode);
when(mockHashNode.getParent()).thenReturn(mockChildNode);
when(mockSession.nodeExists("/some")).thenReturn(true);
when(mockSession.getNode("/some")).thenReturn(mockChildNode);
when(mockChildNode.isNew()).thenReturn(false);
when(testObj.jcrTools.findOrCreateNode(mockSession, "/some/#/abc", NT_FOLDER)).thenReturn(mockNode);
when(mockHashNode.isNew()).thenReturn(true);
final Statement statement = testObj.skolemize(testSubjects, x, "/some/#/abc");
assertEquals(x, statement);
verify(testObj.jcrTools).findOrCreateNode(mockSession, "/some/#/abc", NT_FOLDER);
verify(mockNode).addMixin(FEDORA_RESOURCE);
verify(mockHashNode).addMixin(FEDORA_PAIRTREE);
}
@Test
public void shouldCreateHashUriSubjectsWithExistingHashUri() throws RepositoryException {
final Model m = createDefaultModel();
final Statement x = m.createStatement(testSubjects.toDomain("/some/#/abc"),
createProperty("info:x"),
testSubjects.toDomain("/"));
testObj.jcrTools = mock(JcrTools.class);
when(mockNode.getParent()).thenReturn(mockHashNode);
when(mockHashNode.getParent()).thenReturn(mockChildNode);
when(mockSession.nodeExists("/some")).thenReturn(true);
when(mockSession.getNode("/some")).thenReturn(mockChildNode);
when(mockChildNode.isNew()).thenReturn(false);
when(mockChildNode.hasNode("#")).thenReturn(true);
when(mockChildNode.getNode("#")).thenReturn(mockHashNode);
when(mockHashNode.isNew()).thenReturn(false);
when(testObj.jcrTools.findOrCreateNode(mockSession, "/some/#/abc", NT_FOLDER)).thenReturn(mockNode);
final Statement statement = testObj.skolemize(testSubjects, x, "/some/#/abc");
assertEquals(x, statement);
verify(testObj.jcrTools).findOrCreateNode(mockSession, "/some/#/abc", NT_FOLDER);
verify(mockNode).addMixin(FEDORA_RESOURCE);
}
@Test(expected = PathNotFoundException.class)
public void shouldNotAllowHashUriSubjectsForResourcesThatDontExist() throws RepositoryException {
final Model m = createDefaultModel();
final Statement x = m.createStatement(testSubjects.toDomain("/some/#/abc"),
createProperty("info:x"),
testSubjects.toDomain("/"));
testObj.jcrTools = mock(JcrTools.class);
when(mockNode.getParent()).thenReturn(mockHashNode);
when(mockHashNode.getParent()).thenReturn(mockChildNode);
when(mockSession.nodeExists("/some")).thenReturn(false);
when(testObj.jcrTools.findOrCreateNode(mockSession, "/some/#/abc", NT_FOLDER)).thenReturn(mockNode);
when(FedoraTypesUtils.getClosestExistingAncestor(mockSession,"/some/#/abc"))
.thenReturn(mockNode);
testObj.skolemize(testSubjects, x, "/some");
}
@Test
public void shouldCreateHashUriObjects() throws RepositoryException {
final Model m = createDefaultModel();
final Statement x = m.createStatement(
testSubjects.toDomain("/"),
createProperty("info:x"),
testSubjects.toDomain("/some/#/abc"));
testObj.jcrTools = mock(JcrTools.class);
when(mockNode.getParent()).thenReturn(mockHashNode);
when(mockHashNode.getParent()).thenReturn(mockChildNode);
when(mockSession.nodeExists("/some")).thenReturn(true);
when(mockSession.getNode("/some")).thenReturn(mockChildNode);
when(testObj.jcrTools.findOrCreateNode(mockSession, "/some/#/abc", NT_FOLDER)).thenReturn(mockNode);
final Statement statement = testObj.skolemize(testSubjects, x, "/");
assertEquals(x, statement);
verify(testObj.jcrTools).findOrCreateNode(mockSession, "/some/#/abc", NT_FOLDER);
verify(mockNode).addMixin(FEDORA_RESOURCE);
}
@Test
public void shouldIgnoreHashUrisOutsideTheRepositoryDomain() throws RepositoryException {
final Model m = createDefaultModel();
final Statement x = m.createStatement(
testSubjects.toDomain("/"),
createProperty("info:x"),
createResource("info:x#abc"));
final Statement statement = testObj.skolemize(testSubjects, x, "/");
assertEquals(x, statement);
}
@Mock
private Property mockPredicate;
@Mock
private Function<javax.jcr.Property, org.apache.jena.rdf.model.Property> mockPredicateFactoryFunc;
@Mock
private NodeIterator mockNodes;
@Mock
private NodeIterator mockNodes2;
@Mock
private NodeIterator mockNodes3;
@Mock
private Function<Node, ValueFactory> mockValueFactoryFunc;
@Mock
private Node mockNode;
@Mock
private Node mockNode1;
@Mock
private Node mockNode2;
@Mock
private Node mockNode3;
@Mock
private Node mockParent;
@Mock
private Resource mockSubject;
@Mock
private Resource mockResource;
@Mock
private Session mockSession;
@Mock
private NodeType mockNodeType;
@Mock
private javax.jcr.Property mockProperty;
@Mock
private PropertyDefinition mockPropertyDefinition;
@Mock
private Value mockValue;
@Mock
private Value mockReferenceValue;
@Mock
private Repository mockRepository;
@Mock
private Workspace mockWorkspace;
@Mock
private PropertyIterator mockProperties;
@Mock
private PropertyIterator mockProperties2;
@Mock
private PropertyIterator mockParentProperties;
@Mock
private Node mockContentNode;
@Mock
private Version mockVersion;
@Mock
private Node mockFrozenNode;
@Mock
private VersionManager mockVersionManager;
@Mock
private VersionIterator mockVersionIterator;
@Mock
private VersionHistory mockVersionHistory;
@Mock
private BinaryValue mockBinary;
@Mock
private CacheEntry mockCacheEntry;
@Mock
private QueryManager mockQueryManager;
@Mock
private Query mockQuery;
@Mock
private ValueFactory mockValueFactory;
@Mock
private QueryResult mockQueryResult;
@Mock
private RowIterator mockRowIterator;
@Mock
private MetricRegistry mockMetrics;
@Mock
private Node mockChildNode, mockChildNode2, mockChildNode3, mockChildNode4, mockChildNode5, mockFullChildNode,
mockRootNode, mockHashNode;
@Mock
private Counter mockCounter;
@Mock
private NodeTypeManager mockNodeTypeManager;
@Mock
private NodeTypeIterator mockNodeTypeIterator;
@Mock
private NodeType mockMixinNodeType, mockPrimaryNodeType;
@Mock
private NamespaceRegistry mockNsRegistry;
@Mock
private FedoraResourceImpl mockFedoraResource;
}