Skip to content

Commit

Permalink
Serialize incoming RDF properties to JCR Strings
Browse files Browse the repository at this point in the history
  • Loading branch information
cbeer committed Nov 6, 2014
1 parent abc3fb1 commit 5fe6b25
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 265 deletions.
Expand Up @@ -20,7 +20,6 @@
import static javax.jcr.PropertyType.REFERENCE;
import static javax.jcr.PropertyType.STRING;
import static javax.jcr.PropertyType.UNDEFINED;
import static javax.jcr.PropertyType.URI;
import static javax.jcr.PropertyType.WEAKREFERENCE;
import static org.fcrepo.jcr.FedoraJcrTypes.FEDORA_BLANKNODE;
import static org.fcrepo.jcr.FedoraJcrTypes.FEDORA_PAIRTREE;
Expand Down Expand Up @@ -176,9 +175,8 @@ public Value createValue(final ValueFactory valueFactory, final RDFNode data, fi
throws RepositoryException {
assert (valueFactory != null);

if (type == UNDEFINED
|| type == STRING
|| (data.isResource() && type != URI && type != REFERENCE && type != WEAKREFERENCE)) {

if (type == UNDEFINED || type == STRING) {
return valueConverter.reverse().convert(data);
} else if (type == REFERENCE || type == WEAKREFERENCE) {
// reference to another node (by path)
Expand Down Expand Up @@ -267,7 +265,7 @@ public void addProperty(final FedoraResource resource,
}

final String propertyName =
getPropertyNameFromPredicate(node, predicate, value, namespaces);
getPropertyNameFromPredicate(node, predicate, namespaces);

if (value.isURIResource()
&& idTranslator.inDomain(value.asResource())
Expand Down Expand Up @@ -316,7 +314,7 @@ public void removeProperty(final FedoraResource resource,
final Map<String, String> nsPrefixMap) throws RepositoryException {

final Node node = resource.getNode();
final String propertyName = getPropertyNameFromPredicate(node, predicate, objectNode, nsPrefixMap);
final String propertyName = getPropertyNameFromPredicate(node, predicate, nsPrefixMap);

if (isManagedPredicate.apply(predicate)) {

Expand Down
Expand Up @@ -19,7 +19,6 @@
import com.google.common.base.Converter;
import com.google.common.collect.ImmutableBiMap;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import org.modeshape.jcr.api.NamespaceRegistry;
import org.modeshape.jcr.api.Namespaced;
Expand Down Expand Up @@ -61,8 +60,6 @@ protected Property doForward(final javax.jcr.Property property) {

if (isInternalReferenceProperty.apply(property)) {
rdfLocalName = getReferencePropertyOriginalName(localName);
} else if (localName.contains("@")) {
rdfLocalName = localName.substring(0, localName.indexOf("@"));
} else {
rdfLocalName = localName;
}
Expand Down Expand Up @@ -94,31 +91,11 @@ protected javax.jcr.Property doBackward(final Property property) {
*/
public static String getPropertyNameFromPredicate(final Node node,
final Resource predicate,
final Map<String,String> namespaceMapping)
final Map<String, String> namespaceMapping)
throws RepositoryException {
return getPropertyNameFromPredicate(node, predicate, null, namespaceMapping);
}


/**
* Given an RDF predicate value (namespace URI + local name), figure out
* what JCR property to use
*
* @param node the JCR node we want a property for
* @param predicate the predicate to map to a property name
* @param namespaceMapping prefix to uri namespace mapping
* @return the JCR property name
* @throws RepositoryException
*/
public static String getPropertyNameFromPredicate(final Node node,
final Resource predicate,
final RDFNode object,
final Map<String,String> namespaceMapping) throws RepositoryException {
final NamespaceRegistry namespaceRegistry = getNamespaceRegistry.apply(node);
return getPropertyNameFromPredicate(namespaceRegistry,
predicate,
object,
namespaceMapping);
predicate, namespaceMapping);
}

/**
Expand All @@ -132,7 +109,6 @@ public static String getPropertyNameFromPredicate(final Node node,
*/
public static String getPropertyNameFromPredicate(final NamespaceRegistry namespaceRegistry,
final Resource predicate,
final RDFNode object,
final Map<String, String> namespaceMapping)
throws RepositoryException {

Expand Down Expand Up @@ -162,19 +138,7 @@ public static String getPropertyNameFromPredicate(final NamespaceRegistry namesp
}
}

final StringBuilder stringBuilder = new StringBuilder();

stringBuilder.append(prefix);
stringBuilder.append(":");
stringBuilder.append(rdfLocalname);


if (object != null && object.isLiteral() && !object.asLiteral().getLanguage().isEmpty()) {
stringBuilder.append("@");
stringBuilder.append(object.asLiteral().getLanguage());
}

final String propertyName = stringBuilder.toString();
final String propertyName = prefix + ":" + rdfLocalname;

LOGGER.debug("Took RDF predicate {} and translated it to JCR property {}", namespace, propertyName);

Expand Down
Expand Up @@ -16,9 +16,9 @@
package org.fcrepo.kernel.impl.rdf.converters;

import com.google.common.base.Converter;
import com.google.common.base.Splitter;
import com.hp.hpl.jena.datatypes.BaseDatatype;
import com.hp.hpl.jena.datatypes.RDFDatatype;
import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
Expand All @@ -32,8 +32,10 @@
import javax.jcr.Value;
import javax.jcr.ValueFactory;

import java.math.BigDecimal;
import java.util.Iterator;

import static com.hp.hpl.jena.rdf.model.ResourceFactory.createLangLiteral;
import static com.hp.hpl.jena.rdf.model.ResourceFactory.createPlainLiteral;
import static com.hp.hpl.jena.rdf.model.ResourceFactory.createResource;
import static com.hp.hpl.jena.rdf.model.ResourceFactory.createTypedLiteral;
import static javax.jcr.PropertyType.BOOLEAN;
Expand All @@ -57,8 +59,6 @@
public class ValueConverter extends Converter<Value, RDFNode> {

private static final Logger LOGGER = getLogger(ValueConverter.class);
private static final String LITERAL_TYPE_SEP = "\30^^\30";
private static final String URI_SUFFIX = "URI";

private final Session session;
private final Converter<Node, Resource> graphSubjects;
Expand Down Expand Up @@ -109,55 +109,24 @@ protected Value doBackward(final RDFNode resource) {

final ValueFactory valueFactory = session.getValueFactory();

if (resource.isURIResource()) {
// some random opaque URI
return valueFactory.createValue(resource.toString() + LITERAL_TYPE_SEP + URI_SUFFIX, STRING);
}

if (resource.isResource()) {
if (resource.isAnon()) {
// a non-URI resource (e.g. a blank node)
return valueFactory.createValue(resource.toString(), UNDEFINED);
}

final Literal literal = resource.asLiteral();
final RDFDatatype dataType = literal.getDatatype();
final Object rdfValue;
final RdfLiteralJcrValueBuilder rdfLiteralJcrValueBuilder = new RdfLiteralJcrValueBuilder();

if (literal.asNode().getLiteral().isWellFormed()) {
rdfValue = literal.getValue();
if (resource.isURIResource()) {
rdfLiteralJcrValueBuilder.value(resource.asResource().getURI()).datatype("URI");
} else {
rdfValue = literal.getLexicalForm();
}

if (dataType == null && rdfValue instanceof String
|| (dataType != null && dataType.equals(XSDDatatype.XSDstring))) {
// short-circuit the common case
return valueFactory.createValue(literal.getString(), STRING);
} else if (rdfValue instanceof Boolean) {
return valueFactory.createValue((Boolean) rdfValue);
} else if (rdfValue instanceof Byte
|| (dataType != null && dataType.getJavaClass() == Byte.class)) {

return valueFactory.createValue(literal.getByte());
} else if (rdfValue instanceof Double) {
return valueFactory.createValue(literal.getDouble());
} else if (rdfValue instanceof BigDecimal) {
return valueFactory.createValue((BigDecimal)literal.getValue());
} else if (rdfValue instanceof Float) {
return valueFactory.createValue(literal.getFloat());
} else if (rdfValue instanceof Long
|| (dataType != null && dataType.getJavaClass() == Long.class)) {
return valueFactory.createValue(literal.getLong());
} else if (rdfValue instanceof Short
|| (dataType != null && dataType.getJavaClass() == Short.class)) {
return valueFactory.createValue(literal.getShort());
} else if (rdfValue instanceof Integer) {
return valueFactory.createValue(literal.getInt());
} else if (dataType != null && !dataType.getURI().isEmpty()) {
return valueFactory.createValue(literal.getString() + LITERAL_TYPE_SEP + dataType.getURI(), STRING);
} else {
return valueFactory.createValue(literal.getString(), STRING);
final Literal literal = resource.asLiteral();
final RDFDatatype dataType = literal.getDatatype();

rdfLiteralJcrValueBuilder.value(literal.getString()).datatype(dataType).lang(literal.getLanguage());
}

return valueFactory.createValue(rdfLiteralJcrValueBuilder.toString(), STRING);
} catch (final RepositoryException e) {
throw new RepositoryRuntimeException(e);
}
Expand All @@ -171,19 +140,16 @@ private static Literal literal2node(final Object literal) {


private static RDFNode stringliteral2node(final String literal) {
final int i = literal.indexOf(LITERAL_TYPE_SEP);
final RdfLiteralJcrValueBuilder rdfLiteralJcrValueBuilder = new RdfLiteralJcrValueBuilder(literal);

if (i < 0) {
return literal2node(literal);
if (rdfLiteralJcrValueBuilder.hasLang()) {
return createLangLiteral(rdfLiteralJcrValueBuilder.value(), rdfLiteralJcrValueBuilder.lang());
} else if (rdfLiteralJcrValueBuilder.isResource()) {
return createResource(rdfLiteralJcrValueBuilder.value());
} else if (rdfLiteralJcrValueBuilder.hasDatatypeUri()) {
return createTypedLiteral(rdfLiteralJcrValueBuilder.value(), rdfLiteralJcrValueBuilder.datatype());
} else {
final String value = literal.substring(0, i);
final String datatypeURI = literal.substring(i + LITERAL_TYPE_SEP.length());

if (datatypeURI.equals("URI")) {
return createResource(value);
} else {
return createTypedLiteral(value, new BaseDatatype(datatypeURI));
}
return createPlainLiteral(literal);
}
}

Expand All @@ -201,4 +167,105 @@ private RDFNode traverseLink(final Value v)
private RDFNode getGraphSubject(final javax.jcr.Node n) {
return graphSubjects.convert(n);
}

protected static class RdfLiteralJcrValueBuilder {
private static final String FIELD_DELIMITER = "\30^^\30";
public static final Splitter JCR_VALUE_SPLITTER = Splitter.on(FIELD_DELIMITER);

private String value;
private String datatypeUri;
private String lang;

RdfLiteralJcrValueBuilder() {

}

public RdfLiteralJcrValueBuilder(final String literal) {
this();

final Iterator<String> tokenizer = JCR_VALUE_SPLITTER.split(literal).iterator();

value = tokenizer.next();

if (tokenizer.hasNext()) {
datatypeUri = tokenizer.next();
}

if (tokenizer.hasNext()) {
lang = tokenizer.next();
}
}

public String toString() {
final StringBuilder b = new StringBuilder();

b.append(value);

if (hasDatatypeUri()) {
b.append(FIELD_DELIMITER);
b.append(datatypeUri);
} else if (hasLang()) {
// if it has a language, but not a datatype, add a placeholder.
b.append(FIELD_DELIMITER);
}

if (hasLang()) {
b.append(FIELD_DELIMITER);
b.append(lang);
}

return b.toString();

}

public String value() {
return value;
}

public RDFDatatype datatype() {
if (hasDatatypeUri()) {
return new BaseDatatype(datatypeUri);
} else {
return null;
}
}

public String lang() {
return lang;
}

public RdfLiteralJcrValueBuilder value(final String value) {
this.value = value;
return this;
}

public RdfLiteralJcrValueBuilder datatype(final String datatypeUri) {
this.datatypeUri = datatypeUri;
return this;
}

public RdfLiteralJcrValueBuilder datatype(final RDFDatatype datatypeUri) {
if (datatypeUri != null && !datatypeUri.getURI().isEmpty()) {
this.datatypeUri = datatypeUri.getURI();
}
return this;
}

public RdfLiteralJcrValueBuilder lang(final String lang) {
this.lang = lang;
return this;
}

public boolean hasLang() {
return lang != null && !lang.isEmpty();
}

public boolean hasDatatypeUri() {
return datatypeUri != null && !datatypeUri.isEmpty();
}

public boolean isResource() {
return hasDatatypeUri() && datatypeUri.equals("URI");
}
}
}
Expand Up @@ -22,7 +22,6 @@
import static com.hp.hpl.jena.rdf.model.ResourceFactory.createResource;
import static java.util.Arrays.asList;
import static javax.jcr.PropertyType.BINARY;
import static javax.jcr.PropertyType.LONG;
import static org.fcrepo.jcr.FedoraJcrTypes.FEDORA_CONTAINER;
import static org.fcrepo.jcr.FedoraJcrTypes.FEDORA_NON_RDF_SOURCE_DESCRIPTION;
import static org.fcrepo.jcr.FedoraJcrTypes.FEDORA_RESOURCE;
Expand Down Expand Up @@ -425,25 +424,6 @@ public void testGetObjectVersionGraph() throws RepositoryException {

}

@Test
public void testUpdatingRdfTypedValues() throws RepositoryException {
final FedoraResource object =
containerService.findOrCreate(session, "/testObjectRdfType");

object.updateProperties(
subjects,
"PREFIX example: <http://example.org/>\n"
+ "PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>\n"
+ "INSERT { <"
+ createGraphSubjectNode(object).getURI()
+ "> example:int-property \"0\"^^xsd:long } "
+ "WHERE { }", new RdfStream());
assertEquals(LONG, object.getNode().getProperty("example:int-property")
.getType());
assertEquals(0L, object.getNode().getProperty("example:int-property")
.getValues()[0].getLong());
}

@Test(expected = MalformedRdfException.class)
public void testAddMissingReference() throws RepositoryException, MalformedRdfException {
final FedoraResource object =
Expand Down

0 comments on commit 5fe6b25

Please sign in to comment.