/* The contents of this file are subject to the license and copyright terms * detailed in the license directory at the root of the source tree (also * available online at http://fedora-commons.org/license/). */ package org.fcrepo.server.storage.types; import java.net.URI; import java.net.URISyntaxException; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.jrdf.graph.GraphElementFactory; import org.jrdf.graph.Literal; import org.jrdf.graph.ObjectNode; import org.jrdf.graph.PredicateNode; import org.jrdf.graph.SubjectNode; import org.jrdf.graph.Triple; import org.openrdf.rio.RDFHandlerException; import org.trippi.io.transform.Transformer; import org.fcrepo.common.Constants; import org.fcrepo.common.rdf.SimpleLiteral; import org.fcrepo.common.rdf.SimpleTriple; import org.fcrepo.common.rdf.SimpleURIReference; /** * A data structure for holding relationships. * * @author Robert Haschart */ public class RelationshipTuple implements Constants { public static final Transformer<RelationshipTuple> TRANSFORMER = new TripleTransformer(); public final String subject; public final String predicate; public final String object; public final boolean isLiteral; public final URI datatype; public final String language; public RelationshipTuple(String subject, String predicate, String object, boolean isLiteral, URI datatype) { this(subject, predicate, object, isLiteral, datatype, null); } public RelationshipTuple(String subject, String predicate, String object, boolean isLiteral, URI datatype, String language) { this.subject = subject; this.predicate = predicate; this.object = object; this.isLiteral = isLiteral; this.datatype = datatype; this.language = language; } // TODO: Consider getting rid of this method public String getObjectPID() { if (object != null && !isLiteral && object.startsWith("info:fedora/")) { String PID = object.substring(12); return PID; } return null; } // TODO: Consider getting rid of this method public String getRelationship() { String prefixRel = RELS_EXT.uri; if (predicate != null && predicate.startsWith(prefixRel)) { String rel = "rel:" + predicate.substring(prefixRel.length()); return rel; } String prefixModel = MODEL.uri; if (predicate != null && predicate.startsWith(prefixModel)) { String rel = "fedora-model:" + predicate.substring(prefixModel.length()); return rel; } return predicate; } @Override public String toString() { String retVal = "Sub: " + subject + " Pred: " + predicate + " Obj: [" + object + ", " + isLiteral + ", " + datatype + "]"; return retVal; } @Override public int hashCode() { return hc(subject) + hc(predicate) + hc(object) + hc(datatype); } @Override public boolean equals(Object o) { if (o instanceof RelationshipTuple) { RelationshipTuple t = (RelationshipTuple) o; return eq(subject, t.subject) && eq(predicate, t.predicate) && eq(object, t.object) && eq(datatype, t.datatype) && isLiteral == t.isLiteral; } else { return false; } } public Triple toTriple(Map<String, String> namespaces) throws URISyntaxException { return new SimpleTriple( new SimpleURIReference(new URI(subject)), RelationshipTuple.makePredicateResourceFromRel(predicate, namespaces), RelationshipTuple.makeObjectFromURIandLiteral(object, isLiteral, datatype, language)); } public static URI makePredicateFromRel(String relationship, Map<String,String> map) throws URISyntaxException { String predicate = relationship; if (map != null) { Set<String> keys = map.keySet(); Iterator<String> iter = keys.iterator(); while (iter.hasNext()) { String key = iter.next(); if (predicate.startsWith(key)) { int keyLen = key.length(); if (predicate.length() != keyLen && predicate.charAt(keyLen) == ':') { predicate = map.get(key).concat(predicate.substring(keyLen + 1)); } } } } URI retVal = null; retVal = new URI(predicate); return retVal; } public static PredicateNode makePredicateResourceFromRel(String predicate, Map<String, String> map) throws URISyntaxException { URI predURI = RelationshipTuple.makePredicateFromRel(predicate, map); PredicateNode node = new SimpleURIReference(predURI); return node; } public static ObjectNode makeObjectFromURIandLiteral(String objURI, boolean isLiteral, URI literalType, String language) throws URISyntaxException { ObjectNode obj = null; if (isLiteral) { if (literalType != null) { obj = new SimpleLiteral(objURI, literalType); } else if (language != null){ obj = new SimpleLiteral(objURI, language); } else { obj = new SimpleLiteral(objURI); } } else { obj = new SimpleURIReference(new URI(objURI)); } return obj; } public static RelationshipTuple fromTriple(Triple triple) { return fromNodes(triple.getSubject(), triple.getPredicate(), triple.getObject()); } public static RelationshipTuple fromNodes( SubjectNode sNode, PredicateNode pNode, ObjectNode oNode) { String subject = sNode.toString(); String predicate = pNode.toString(); if (oNode instanceof Literal) { return getLiteral(subject, predicate, (Literal)oNode); } else { return new RelationshipTuple(subject, predicate, oNode.toString(), false, null, null); } } public static RelationshipTuple fromNodes(org.openrdf.model.Resource s, org.openrdf.model.URI p, org.openrdf.model.Value o, GraphElementFactory u) { String subject = s.stringValue(); String predicate = p.stringValue(); // the rdf streams parsed by Fedora will only contain URIs and Literals, no BNodes if (o instanceof org.openrdf.model.Literal) { return getLiteral(subject, predicate, (org.openrdf.model.Literal)o); } else { return new RelationshipTuple(subject, predicate, o.stringValue(), false, null, null); } } private static RelationshipTuple getLiteral(String subject, String predicate, Literal literal) { return new RelationshipTuple(subject, predicate, literal.getLexicalForm(), true, literal.getDatatypeURI(), literal.getLanguage()); } private static RelationshipTuple getLiteral(String subject, String predicate, org.openrdf.model.Literal literal) { if (literal.getDatatype() != null) { return new RelationshipTuple(subject, predicate, literal.stringValue(), true, URI.create(literal.getDatatype().stringValue()), null); } else { return new RelationshipTuple(subject, predicate, literal.stringValue(), true, null, literal.getLanguage()); } } // test for equality, accounting for null values private static boolean eq(Object a, Object b) { if (a == null) { return b == null; } else { return b != null && a.equals(b); } } // return the hashCode or 0 if null private static int hc(Object o) { if (o == null) { return 0; } else { return o.hashCode(); } } public static class TripleTransformer implements Transformer<RelationshipTuple> { @Override public RelationshipTuple transform(Triple input) { return RelationshipTuple.fromTriple(input); } @Override public RelationshipTuple transform( SubjectNode sNode, PredicateNode pNode, ObjectNode oNode) { return RelationshipTuple.fromNodes(sNode, pNode, oNode); } @Override public RelationshipTuple transform(org.openrdf.model.Statement s, GraphElementFactory u) throws RDFHandlerException { return RelationshipTuple.fromNodes(s.getSubject(), s.getPredicate(), s.getObject(), u); } } }