package org.ontoware.rdf2go.impl.jena; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; import java.net.URISyntaxException; import java.util.Iterator; import java.util.Map; import org.apache.jena.riot.Lang; import org.apache.jena.riot.RDFDataMgr; import org.apache.jena.riot.RDFLanguages; import org.apache.jena.riot.RDFWriterRegistry; import org.ontoware.aifbcommons.collection.ClosableIterable; import org.ontoware.aifbcommons.collection.ClosableIterator; import org.ontoware.rdf2go.Reasoning; import org.ontoware.rdf2go.exception.LockException; import org.ontoware.rdf2go.exception.ModelRuntimeException; import org.ontoware.rdf2go.exception.QueryLanguageNotSupportedException; import org.ontoware.rdf2go.exception.SyntaxNotSupportedException; import org.ontoware.rdf2go.model.DiffReader; import org.ontoware.rdf2go.model.Model; import org.ontoware.rdf2go.model.QueryResultTable; import org.ontoware.rdf2go.model.Statement; import org.ontoware.rdf2go.model.Syntax; import org.ontoware.rdf2go.model.impl.AbstractModel; import org.ontoware.rdf2go.model.node.BlankNode; import org.ontoware.rdf2go.model.node.DatatypeLiteral; import org.ontoware.rdf2go.model.node.NodeOrVariable; import org.ontoware.rdf2go.model.node.ResourceOrVariable; import org.ontoware.rdf2go.model.node.URI; import org.ontoware.rdf2go.model.node.UriOrVariable; import org.ontoware.rdf2go.model.node.impl.AbstractBlankNodeImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.hp.hpl.jena.graph.Node; import com.hp.hpl.jena.graph.Triple; import com.hp.hpl.jena.query.Query; import com.hp.hpl.jena.query.QueryExecution; import com.hp.hpl.jena.query.QueryExecutionFactory; import com.hp.hpl.jena.query.QueryFactory; import com.hp.hpl.jena.rdf.model.AnonId; import com.hp.hpl.jena.rdf.model.Literal; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.rdf.model.impl.RDFReaderFImpl; import com.hp.hpl.jena.rdf.model.impl.RDFWriterFImpl; import com.hp.hpl.jena.reasoner.ReasonerRegistry; import com.hp.hpl.jena.shared.BadURIException; // import de.fuberlin.wiwiss.ng4j.triql.TriQLQuery; /** * * (wth) for information on typed literals see this very good how to * http://jena.sourceforge.net/how-to/typedLiterals.html * */ public class ModelImplJena extends AbstractModel implements Model { private static final long serialVersionUID = -2993918177017878243L; protected static final Logger log = LoggerFactory.getLogger(ModelImplJena.class); protected com.hp.hpl.jena.rdf.model.Model jenaModel; /** * used to check whether iterators work on the up-to-date model */ protected long modificationCount = 0; protected Reasoning reasoning; private final URI contextURI; private boolean locked; /** * @param contextURI the first part of the quad, never null * @param reasoning never null */ public ModelImplJena(URI contextURI, Reasoning reasoning) { this(contextURI, ModelFactory.createDefaultModel(), reasoning); } /** * wraps a Jena Model in a rdf2go Model * * @param jenaModel to be wrapped into an RDF2Go Model */ public ModelImplJena(URI contextURI, com.hp.hpl.jena.rdf.model.Model jenaModel) { this(contextURI, jenaModel, Reasoning.none); } public ModelImplJena(com.hp.hpl.jena.rdf.model.Model jenaModel) { this(null, jenaModel, Reasoning.none); } public ModelImplJena(URI contextURI, com.hp.hpl.jena.rdf.model.Model jenaModel, Reasoning reasoning) { this.contextURI = contextURI; this.reasoning = reasoning; // re-use this.jenaModel = jenaModel; //wires RIOT readers/writers into Jena org.apache.jena.riot.RIOT.init(); // Fix for Jena lowercase language name "N-Triples": RDFReaderFImpl.setBaseReaderClassName("N-Triples", com.hp.hpl.jena.rdf.model.impl.NTripleReader.class.getName()) ; RDFWriterFImpl.setBaseWriterClassName("N-Triples", com.hp.hpl.jena.rdf.model.impl.NTripleWriter.class.getName()); applyReasoning(reasoning); } public ModelImplJena(Reasoning reasoning) { this(null, reasoning); } @Override public void addAll(Iterator<? extends Statement> other) throws ModelRuntimeException { assertModel(); if(other instanceof ModelImplJena) { com.hp.hpl.jena.rdf.model.Model otherJenaModel = (com.hp.hpl.jena.rdf.model.Model)((ModelImplJena)other) .getUnderlyingModelImplementation(); this.jenaModel.add(otherJenaModel); } else super.addAll(other); } void applyReasoning(Reasoning r) { switch(r) { case rdfs: this.jenaModel = ModelFactory.createRDFSModel(this.jenaModel); break; case owl: this.jenaModel = ModelFactory.createInfModel(ReasonerRegistry.getOWLReasoner(), this.jenaModel); break; default: break; } } @Override public BlankNode createBlankNode() { // this.modificationCount++; // should be unique across models return new JenaBlankNode(com.hp.hpl.jena.graph.NodeFactory.createAnon()); } @Override public BlankNode createBlankNode(String id) { // this.modificationCount++; // should be unique across models AnonId anonid = AnonId.create(id); return new JenaBlankNode(com.hp.hpl.jena.graph.NodeFactory.createAnon(anonid)); } /* * (non-Javadoc) * * @see org.ontoware.rdf2go.Model#addStatement(java.lang.Object, * java.net.URI, java.lang.Object) */ @Override public void addStatement(org.ontoware.rdf2go.model.node.Resource subject, URI predicate, org.ontoware.rdf2go.model.node.Node object) throws ModelRuntimeException { assertModel(); try { log.debug("adding a statement (" + subject + "," + predicate + "," + object + ")"); this.modificationCount++; if(!(object instanceof DatatypeLiteral)) { this.jenaModel.getGraph().add( new Triple(TypeConversion.toJenaNode(subject, this.jenaModel), TypeConversion.toJenaNode(predicate, this.jenaModel), TypeConversion.toJenaNode(object, this.jenaModel))); } else // DatatypeLiteral { // build Resources/Literals Resource s = null; if(subject instanceof URI) { s = this.jenaModel.createResource(subject.toString()); } else // subject is a BlankNode { s = this.jenaModel.createResource(((Node)((AbstractBlankNodeImpl)subject) .getUnderlyingBlankNode()).getBlankNodeId()); } Property p = this.jenaModel.createProperty(predicate.toString()); String datatypeValue = ((DatatypeLiteral)object).getValue(); String datatypeURI = ((DatatypeLiteral)object).getDatatype().toString(); Literal o = this.jenaModel.createTypedLiteral(datatypeValue, datatypeURI); // Add the statement to the model this.jenaModel.add(s, p, o); } } catch(BadURIException e) { throw new ModelRuntimeException(e); } } /* * (non-Javadoc) * * @see org.ontoware.rdf2go.Model#removeStatement(java.lang.Object, * java.net.URI, java.lang.Object) */ @Override public void removeStatement(org.ontoware.rdf2go.model.node.Resource subject, URI predicate, org.ontoware.rdf2go.model.node.Node object) throws ModelRuntimeException { assertModel(); log.debug("removing a statement (" + subject + "," + predicate + "," + object + ")"); this.modificationCount++; this.jenaModel.getGraph().delete( new Triple( TypeConversion.toJenaNode(subject, this.jenaModel), TypeConversion.toJenaNode( predicate, this.jenaModel), TypeConversion.toJenaNode(object, this.jenaModel))); } @Override public QueryResultTable sparqlSelect(String queryString) throws ModelRuntimeException { assertModel(); log.debug("Query " + queryString); Query query = QueryFactory.create(queryString); return new QueryResultTableImpl(query, this.jenaModel); } @Override public ClosableIterable<Statement> sparqlConstruct(String queryString) throws ModelRuntimeException { assertModel(); Query query = QueryFactory.create(queryString); QueryExecution qexec = QueryExecutionFactory.create(query, this.jenaModel); if(query.isConstructType()) { com.hp.hpl.jena.rdf.model.Model m = qexec.execConstruct(); Model resultModel = new ModelImplJena(null, m, Reasoning.none); resultModel.open(); return resultModel; } else { throw new RuntimeException("Cannot handle this type of queries! Please use CONSTRUCT."); } } @Override public boolean sparqlAsk(String queryString) throws ModelRuntimeException { assertModel(); log.debug("Query " + queryString); Query query = QueryFactory.create(queryString); if(!query.isAskType()) { throw new ModelRuntimeException("The given query is not an ASK query"); } // else QueryExecution qexec = QueryExecutionFactory.create(query, this.jenaModel); return qexec.execAsk(); } /** * @return opened result Model */ @Override public ClosableIterable<Statement> sparqlDescribe(String queryString) throws ModelRuntimeException { assertModel(); Query query = QueryFactory.create(queryString); QueryExecution qexec = QueryExecutionFactory.create(query, this.jenaModel); if(query.isDescribeType()) { com.hp.hpl.jena.rdf.model.Model m = qexec.execDescribe(); Model resultModel = new ModelImplJena(null, m, Reasoning.none); resultModel.open(); return resultModel; } else { throw new RuntimeException("Cannot handle this type of queries! Please use DESCRIBE."); } } /** * handle with care, iterators based on this model might (silently!) throw * concurrent modification exceptions * * @return the underlying jena model */ public com.hp.hpl.jena.rdf.model.Model getInternalJenaModel() { assertModel(); return this.jenaModel; } /* * (non-Javadoc) * * @see org.ontoware.rdf2go.Model#size() */ @Override public long size() throws ModelRuntimeException { assertModel(); return (int)this.jenaModel.size(); } /** * @return count of modifications, used to prevent iterators from accessing * old modle state */ public long getModificationCount() { return this.modificationCount; } @Override public Object getUnderlyingModelImplementation() { return this.jenaModel; } public void setUnderlyingModelImplementation(Object o) { assert o instanceof com.hp.hpl.jena.rdf.model.Model; this.jenaModel = (com.hp.hpl.jena.rdf.model.Model)o; } @Override public ClosableIterator<Statement> iterator() { assertModel(); return new TripleIterator(this.jenaModel.getGraph().find(Node.ANY, Node.ANY, Node.ANY), this.modificationCount, this); } @Override public URI getContextURI() { return this.contextURI; } @Override public void lock() throws LockException { this.locked = true; this.jenaModel.enterCriticalSection(true); } @Override public boolean isLocked() { return this.locked; } @Override public void unlock() { assertModel(); if(this.isLocked()) { this.jenaModel.leaveCriticalSection(); this.locked = false; } } @Override public synchronized void update(DiffReader diff) throws ModelRuntimeException { assertModel(); lock(); removeAll(diff.getRemoved().iterator()); addAll(diff.getAdded().iterator()); unlock(); } @Override public ClosableIterator<Statement> findStatements(ResourceOrVariable subject, UriOrVariable predicate, NodeOrVariable object) throws ModelRuntimeException { assertModel(); return new TripleIterator(this.jenaModel.getGraph().find( TypeConversion.toJenaNode(subject), TypeConversion.toJenaNode(predicate), TypeConversion.toJenaNode(object)), this.modificationCount, this); } @Override public void readFrom(Reader r) { readFrom(r, Syntax.RdfXml); } @Override public void readFrom(Reader reader, Syntax syntax) { readFrom(reader, syntax, ""); } @Override public void readFrom(Reader reader, Syntax syntax, String baseURI) { assertModel(); RDFDataMgr.read(this.jenaModel, reader, baseURI, getJenaLang(syntax)); } private static void registerNamespaces(com.hp.hpl.jena.rdf.model.Model jenaModel) { // beautify output jenaModel.setNsPrefix("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); jenaModel.setNsPrefix("xsd", "http://www.w3.org/2001/XMLSchema#"); jenaModel.setNsPrefix("rdfs", "http://www.w3.org/2000/01/rdf-schema#"); jenaModel.setNsPrefix("foaf", "http://xmlns.com/foaf/0.1/"); } // TODO: check valid XML output @Override public void writeTo(Writer w) { writeTo(w, Syntax.RdfXml); } @Override public void writeTo(Writer writer, Syntax syntax) { assertModel(); registerNamespaces(this.jenaModel); RDFDataMgr.write(writer, this.jenaModel, RDFWriterRegistry.defaultSerialization(getJenaLang(syntax))); } @Override public void dump() { writeTo(System.out, Syntax.Turtle); } @Override public void readFrom(InputStream in) throws IOException, ModelRuntimeException { readFrom(in, Syntax.RdfXml); } @Override public void readFrom(InputStream in, Syntax syntax) throws IOException, ModelRuntimeException { readFrom(in, syntax, ""); } @Override public void readFrom(InputStream in, Syntax syntax, String baseURI) throws IOException, ModelRuntimeException { assertModel(); assert in != null; RDFDataMgr.read(this.jenaModel, in, baseURI, getJenaLang(syntax)); } @Override public void writeTo(OutputStream out) throws ModelRuntimeException { writeTo(out, Syntax.RdfXml); } /** * Throws an exception if the syntax is not SPARQL * * @throws IOException from underlying {@link OutputStream} * @throws ModelRuntimeException for errors using the model */ @Override public void writeTo(OutputStream out, Syntax syntax) throws ModelRuntimeException { assertModel(); RDFDataMgr.write(out, this.jenaModel, getJenaLang(syntax)); } /** * Resolves an RDF2Go {@Link Syntax} to a Jena {@link Lang}. * * @param syntax * The RDF2Go Syntax to resolve. * @return A {@link Lang} for the specified syntax. * @throws SyntaxNotSupportedException * When the Syntax could not be resolved to a {@link Lang}. */ public static Lang getJenaLang(Syntax syntax) throws SyntaxNotSupportedException { for (String mimeType : syntax.getMimeTypes()) { Lang lang = RDFLanguages.contentTypeToLang(mimeType); if (lang != null) { return lang; } } throw new SyntaxNotSupportedException("This version of Jena seems to have no " + "support for " + syntax); } @Override public boolean isIsomorphicWith(Model other) { if(other instanceof ModelImplJena) { return this.jenaModel.isIsomorphicWith(((ModelImplJena)other).getInternalJenaModel()); } else { // TODO: reasoning might be different ModelImplJena otherJenaModel = new ModelImplJena(Reasoning.none); otherJenaModel.addAll(other.iterator()); return this.jenaModel.isIsomorphicWith(otherJenaModel.getInternalJenaModel()); } } @Override public boolean isValidURI(String uriString) { try { java.net.URI u = new java.net.URI(uriString); if (!u.isAbsolute()) { throw new URISyntaxException(uriString, "URI is not absolute"); } return true; } catch (URISyntaxException e) { log.debug("Only well-formed absolute URIrefs can be included in RDF/XML output: <" + uriString + "> " + e.getMessage()); return false; } } @Override public String getNamespace(String prefix) { return this.jenaModel.getNsPrefixURI(prefix); } @Override public Map<String,String> getNamespaces() { return this.jenaModel.getNsPrefixMap(); } @Override public void removeNamespace(String prefix) { this.jenaModel.removeNsPrefix(prefix); } @Override public void setNamespace(String prefix, String namespaceURI) throws IllegalArgumentException { this.jenaModel.setNsPrefix(prefix, namespaceURI); } @Override public QueryResultTable querySelect(String queryString, String querylanguage) throws QueryLanguageNotSupportedException, ModelRuntimeException { assertModel(); if(log.isDebugEnabled()) { log.debug("Query " + queryString); } com.hp.hpl.jena.query.Syntax syntax = com.hp.hpl.jena.query.Syntax.lookup(querylanguage); if(syntax == null) { // delegate to super return super.querySelect(queryString, querylanguage); } Query query = QueryFactory.create(queryString, syntax); return new QueryResultTableImpl(query, this.jenaModel); } /** * Throws an exception if the syntax is not SPARQL */ @Override public ClosableIterable<Statement> queryConstruct(String queryString, String querylanguage) throws QueryLanguageNotSupportedException, ModelRuntimeException { assertModel(); com.hp.hpl.jena.query.Syntax syntax = com.hp.hpl.jena.query.Syntax.lookup(querylanguage); if(syntax == null) { // delegate to super return super.queryConstruct(queryString, querylanguage); } Query query = QueryFactory.create(queryString, syntax); QueryExecution qexec = QueryExecutionFactory.create(query, this.jenaModel); if(query.isConstructType()) { com.hp.hpl.jena.rdf.model.Model m = qexec.execConstruct(); Model resultModel = new ModelImplJena(null, m, Reasoning.none); resultModel.open(); return resultModel; } else { throw new RuntimeException("Cannot handle this type of queries! Please use CONSTRUCT."); } } @Override public boolean isEmpty() { return this.jenaModel.isEmpty(); } @Override public void removeAll() throws ModelRuntimeException { this.jenaModel.removeAll(); } @Override public void addModel(Model model) { if (model.getUnderlyingModelImplementation() instanceof com.hp.hpl.jena.rdf.model.Model) { com.hp.hpl.jena.rdf.model.Model otherJenaModel = (com.hp.hpl.jena.rdf.model.Model) model .getUnderlyingModelImplementation(); this.jenaModel.add(otherJenaModel); } else { super.addModel(model); } } }