/* * (C) Copyright 2006-2012 Nuxeo SA (http://nuxeo.com/) and others. * * Licensed 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. * * Contributors: * Anahide Tchertchian * Florent Guillaume */ package org.nuxeo.ecm.platform.relations.jena; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuxeo.ecm.platform.relations.api.Blank; import org.nuxeo.ecm.platform.relations.api.Graph; import org.nuxeo.ecm.platform.relations.api.GraphDescription; import org.nuxeo.ecm.platform.relations.api.Literal; import org.nuxeo.ecm.platform.relations.api.Node; import org.nuxeo.ecm.platform.relations.api.QueryResult; import org.nuxeo.ecm.platform.relations.api.Resource; import org.nuxeo.ecm.platform.relations.api.Statement; import org.nuxeo.ecm.platform.relations.api.impl.NodeFactory; import org.nuxeo.ecm.platform.relations.api.impl.QueryResultImpl; import org.nuxeo.ecm.platform.relations.api.impl.StatementImpl; import org.nuxeo.runtime.datasource.ConnectionHelper; import com.hp.hpl.jena.datatypes.BaseDatatype; import com.hp.hpl.jena.db.DBConnection; import com.hp.hpl.jena.graph.Triple; import com.hp.hpl.jena.graph.impl.LiteralLabel; 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.query.QuerySolution; import com.hp.hpl.jena.query.ResultSet; import com.hp.hpl.jena.rdf.model.AnonId; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.ModelMaker; import com.hp.hpl.jena.rdf.model.NodeIterator; import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.RSIterator; import com.hp.hpl.jena.rdf.model.ReifiedStatement; import com.hp.hpl.jena.rdf.model.ResIterator; import com.hp.hpl.jena.rdf.model.SimpleSelector; import com.hp.hpl.jena.rdf.model.StmtIterator; import com.hp.hpl.jena.shared.Lock; /** * Jena plugin for NXRelations. * <p> * Graph implementation using the <a href="http://jena.sourceforge.net/" target="_blank">Jena</a> framework. */ public class JenaGraph implements Graph { private static final long serialVersionUID = 1L; private static final Log log = LogFactory.getLog(JenaGraph.class); // keep model in a private field for memory graph (only useful for tests ; // not thread safe) private transient Model memoryGraph; private String name; /** * Backend type, default is memory, other possible value is "sql". */ private String backend = "memory"; /** * Database-related options, see http://jena.sourceforge.net/DB/options.html. */ private String datasource; private String databaseType; private boolean databaseDoCompressUri; private boolean databaseTransactionEnabled; private Map<String, String> namespaces = new HashMap<String, String>(); /** * Class holding graph and connection so that we can close the connection after having used the graph. * <p> * It can hold the jena connection or the base connection (built from a datasource). */ protected static final class GraphConnection { private final Connection baseConnection; private final DBConnection connection; private final Model graph; GraphConnection(DBConnection connection, Model graph) { baseConnection = null; this.connection = connection; this.graph = graph; } GraphConnection(Connection baseConnection, Model graph) { this.baseConnection = baseConnection; connection = null; this.graph = graph; } public Model getGraph() { return graph; } protected void close() { if (connection != null) { try { connection.close(); } catch (SQLException e) { log.error("Could not close connection"); } } if (baseConnection != null) { try { baseConnection.close(); } catch (SQLException e) { log.error("Could not close base connection"); } } } } /** * Generates the Jena graph using options. * * @return the Jena graph (model) */ protected GraphConnection openGraph() { return openGraph(false); } /** * Gets the Jena graph using options. * <p> * The Jena "Convenient" reification style is used when opening models: it allows to ignore reification quadlets * when calling the statements list. * * @param forceReload boolean stating if the jena graph has to be reloaded using options * @return the Jena graph (model) */ protected synchronized GraphConnection openGraph(boolean forceReload) { // create model given backend if (backend.equals("memory")) { if (memoryGraph == null || forceReload) { memoryGraph = ModelFactory.createDefaultModel(ModelFactory.Convenient); memoryGraph.setNsPrefixes(namespaces); } return new GraphConnection((Connection) null, memoryGraph); } else if (backend.equals("sql")) { if (datasource == null) { throw new IllegalArgumentException("Missing datasource for sql graph : " + name); } // create a database connection Connection baseConnection; try { baseConnection = ConnectionHelper.getConnection(datasource); } catch (SQLException e) { throw new IllegalArgumentException(String.format("SQLException while opening %s", datasource), e); } /* * We have to wrap the connection to disallow any commit() or setAutoCommit() on it. Jena calls these * methods without regard to the fact that the connection may be managed by an external transaction. */ Connection wrappedConnection = (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), new Class[] { Connection.class }, new ConnectionFixInvocationHandler(baseConnection)); DBConnection connection = new DBConnection(wrappedConnection, databaseType); // check if named model already exists Model graph; if (connection.containsModel(name)) { ModelMaker m = ModelFactory.createModelRDBMaker(connection, ModelFactory.Convenient); graph = m.openModel(name); } else { // create it // check if other models already exist for that connection. if (connection.getAllModelNames().hasNext()) { // other models already exist => do not set parameters // on driver. if (databaseDoCompressUri != connection.getDriver().getDoCompressURI()) { log.warn(String.format("Cannot set databaseDoCompressUri attribute to %s " + "for model %s, other models already " + "exist with value %s", databaseDoCompressUri, name, connection.getDriver().getDoCompressURI())); } if (databaseTransactionEnabled != connection.getDriver().getIsTransactionDb()) { log.warn(String.format("Cannot set databaseTransactionEnabled attribute to %s " + "for model %s, other models already " + "exist with value %s", databaseTransactionEnabled, name, connection.getDriver().getIsTransactionDb())); } } else { if (databaseDoCompressUri) { connection.getDriver().setDoCompressURI(true); } if (databaseTransactionEnabled) { connection.getDriver().setIsTransactionDb(true); } } ModelMaker m = ModelFactory.createModelRDBMaker(connection, ModelFactory.Convenient); graph = m.createModel(name); } graph.setNsPrefixes(namespaces); // use baseConnection so that it is closed instead of the jena one // (to let the pool handled closure). if (baseConnection != null) { return new GraphConnection(baseConnection, graph); } return new GraphConnection(connection, graph); } else { throw new IllegalArgumentException("Unknown backend type " + backend); } } /** * Gets the Jena node for given NXRelations Node instance. * * @param nuxNode NXrelations Node instance * @return Jena node instance */ private static com.hp.hpl.jena.graph.Node getJenaNode(Node nuxNode) { if (nuxNode == null) { return null; } com.hp.hpl.jena.graph.Node jenaNodeInst; if (nuxNode.isBlank()) { Blank blank = (Blank) nuxNode; String id = blank.getId(); if (id == null) { jenaNodeInst = com.hp.hpl.jena.graph.Node.createAnon(); } else { jenaNodeInst = com.hp.hpl.jena.graph.Node.createAnon(new AnonId(id)); } } else if (nuxNode.isLiteral()) { Literal lit = (Literal) nuxNode; String value = lit.getValue(); if (value == null) { throw new IllegalArgumentException(String.format("Invalid literal node %s", nuxNode)); } String language = lit.getLanguage(); String type = lit.getType(); if (language != null) { jenaNodeInst = com.hp.hpl.jena.graph.Node.createLiteral(value, language, false); } else if (type != null) { jenaNodeInst = com.hp.hpl.jena.graph.Node.createLiteral(value, null, new BaseDatatype(type)); } else { jenaNodeInst = com.hp.hpl.jena.graph.Node.createLiteral(value); } } else if (nuxNode.isResource()) { Resource resource = (Resource) nuxNode; String uri = resource.getUri(); jenaNodeInst = com.hp.hpl.jena.graph.Node.createURI(uri); } else { throw new IllegalArgumentException(String.format("Invalid NXRelations node %s", nuxNode)); } return jenaNodeInst; } /** * Gets NXRelations node instance given Jena node. * * @param jenaNodeInst * @return NXRelations node instance */ private Node getNXRelationsNode(com.hp.hpl.jena.graph.Node jenaNodeInst) { if (jenaNodeInst == null) { return null; } Node nuxNode = null; if (jenaNodeInst.isBlank()) { AnonId anonId = jenaNodeInst.getBlankNodeId(); String id = anonId.getLabelString(); nuxNode = NodeFactory.createBlank(id); } else if (jenaNodeInst.isLiteral()) { LiteralLabel label = jenaNodeInst.getLiteral(); String value = label.getLexicalForm(); String type = jenaNodeInst.getLiteralDatatypeURI(); String language = jenaNodeInst.getLiteralLanguage(); if (type != "") { nuxNode = NodeFactory.createTypedLiteral(value, type); } else if (language != "") { nuxNode = NodeFactory.createLiteral(value, language); } else { nuxNode = NodeFactory.createLiteral(value); } } else if (jenaNodeInst.isURI()) { String uri = jenaNodeInst.getURI(); // try to find corresponding prefix // TODO AT: maybe take namespaces from relation service? for (Map.Entry<String, String> ns : namespaces.entrySet()) { String base = ns.getValue(); if (uri.startsWith(base)) { String localName = uri.substring(base.length()); nuxNode = NodeFactory.createQNameResource(base, localName); break; } } if (nuxNode == null) { // default to resource nuxNode = NodeFactory.createResource(uri); } } else { throw new IllegalArgumentException("Cannot translate non concrete Jena node into NXRelations node"); } return nuxNode; } /** * Gets Jena statement selector corresponding to the NXRelations statement. * * @param graph the jena graph * @param nuxStatement NXRelations statement * @return jena statement selector */ private static SimpleSelector getJenaSelector(Model graph, Statement nuxStatement) { com.hp.hpl.jena.rdf.model.Resource subjResource = null; com.hp.hpl.jena.graph.Node subject = getJenaNode(nuxStatement.getSubject()); if (subject != null && subject.isURI()) { subjResource = graph.getResource(subject.getURI()); } Property predProp = null; com.hp.hpl.jena.graph.Node predicate = getJenaNode(nuxStatement.getPredicate()); if (predicate != null && predicate.isURI()) { predProp = graph.getProperty(predicate.getURI()); } com.hp.hpl.jena.graph.Node object = getJenaNode(nuxStatement.getObject()); RDFNode objRDF = null; if (object != null) { objRDF = graph.asRDFNode(object); } return new SimpleSelector(subjResource, predProp, objRDF); } /** * Gets NXRelations statement corresponding to the Jena statement. * <p> * Reified statements may be retrieved from the Jena graph and set as properties on NXRelations statements. * * @param graph the jena graph * @param jenaStatement jena statement * @return NXRelations statement */ private Statement getNXRelationsStatement(Model graph, com.hp.hpl.jena.rdf.model.Statement jenaStatement) { Node subject = getNXRelationsNode(jenaStatement.getSubject().asNode()); Node predicate = getNXRelationsNode(jenaStatement.getPredicate().asNode()); Node object = getNXRelationsNode(jenaStatement.getObject().asNode()); Statement statement = new StatementImpl(subject, predicate, object); // take care of properties if (graph.isReified(jenaStatement)) { com.hp.hpl.jena.rdf.model.Resource reifiedStmt = graph.getAnyReifiedStatement(jenaStatement); StmtIterator it = reifiedStmt.listProperties(); while (it.hasNext()) { com.hp.hpl.jena.rdf.model.Statement stmt = it.nextStatement(); Node nuxNode = getNXRelationsNode(stmt.getPredicate().asNode()); // ugly cast as a Resource Node value = getNXRelationsNode(stmt.getObject().asNode()); statement.addProperty((Resource) nuxNode, value); } } return statement; } /** * Gets NXRelations statement list corresponding to the Jena statement list. * * @param graph the jena graph * @param jenaStatements jena statements list * @return NXRelations statements list */ private List<Statement> getNXRelationsStatements(Model graph, List<com.hp.hpl.jena.rdf.model.Statement> jenaStatements) { List<Statement> nuxStmts = new ArrayList<Statement>(); for (com.hp.hpl.jena.rdf.model.Statement jenaStmt : jenaStatements) { // NXP-2665: remove reified statements are they're as properties in // nuxeo logic if (!jenaStmt.getSubject().canAs(ReifiedStatement.class)) { nuxStmts.add(getNXRelationsStatement(graph, jenaStmt)); } } return nuxStmts; } // Interface implementation @Override public void setDescription(GraphDescription graphDescription) { name = graphDescription.getName(); setOptions(graphDescription.getOptions()); setNamespaces(graphDescription.getNamespaces()); } protected void setOptions(Map<String, String> options) { for (Map.Entry<String, String> option : options.entrySet()) { String key = option.getKey(); String value = option.getValue(); if (key.equals("backend")) { if (value.equals("memory") || value.equals("sql")) { backend = value; } else { throw new IllegalArgumentException(String.format("Unknown backend %s for Jena graph", value)); } } else if (key.equals("datasource")) { datasource = value; } else if (key.equals("databaseType")) { databaseType = value; } else if (key.equals("databaseDoCompressUri")) { if (value.equals("true")) { databaseDoCompressUri = true; } else if (value.equals("false")) { databaseDoCompressUri = false; } else { String format = "Illegal value %s for databaseDoCompressUri, must be true or false"; throw new IllegalArgumentException(String.format(format, value)); } } else if (key.equals("databaseTransactionEnabled")) { if (value.equals("true")) { databaseTransactionEnabled = true; } else if (value.equals("false")) { databaseTransactionEnabled = false; } else { String format = "Illegal value %s for databaseTransactionEnabled, must be true or false"; throw new IllegalArgumentException(String.format(format, value)); } } } } public void setNamespaces(Map<String, String> namespaces) { this.namespaces = namespaces; } @Override public Map<String, String> getNamespaces() { return namespaces; } @Override public void add(Statement statement) { add(Collections.singletonList(statement)); } @Override public void add(List<Statement> statements) { Model graph = null; GraphConnection graphConnection = null; try { graphConnection = openGraph(); graph = graphConnection.getGraph(); graph.enterCriticalSection(Lock.WRITE); for (Statement nuxStmt : statements) { com.hp.hpl.jena.graph.Node subject = getJenaNode(nuxStmt.getSubject()); com.hp.hpl.jena.graph.Node predicate = getJenaNode(nuxStmt.getPredicate()); com.hp.hpl.jena.graph.Node object = getJenaNode(nuxStmt.getObject()); Triple jenaTriple = Triple.create(subject, predicate, object); com.hp.hpl.jena.rdf.model.Statement jenaStmt = graph.asStatement(jenaTriple); // properties Map<Resource, Node[]> properties = nuxStmt.getProperties(); if (properties == null || properties.isEmpty()) { // no properties graph.add(jenaStmt); } else { List<com.hp.hpl.jena.rdf.model.Statement> stmts = new ArrayList<com.hp.hpl.jena.rdf.model.Statement>(); stmts.add(jenaStmt); // create reified statement if it does not exist com.hp.hpl.jena.graph.Node reifiedStmt = graph.getAnyReifiedStatement(jenaStmt).asNode(); for (Map.Entry<Resource, Node[]> property : properties.entrySet()) { com.hp.hpl.jena.graph.Node prop = getJenaNode(property.getKey()); for (Node node : property.getValue()) { com.hp.hpl.jena.graph.Node value = getJenaNode(node); Triple propTriple = Triple.create(reifiedStmt, prop, value); stmts.add(graph.asStatement(propTriple)); } } graph.add(stmts); } } } finally { if (graph != null) { graph.leaveCriticalSection(); } if (graphConnection != null) { graphConnection.close(); } } } @Override public void remove(Statement statement) { remove(Collections.singletonList(statement)); } @Override public void remove(List<Statement> statements) { Model graph = null; GraphConnection graphConnection = null; try { graphConnection = openGraph(); graph = graphConnection.getGraph(); graph.enterCriticalSection(Lock.WRITE); for (Statement nuxStmt : statements) { com.hp.hpl.jena.graph.Node subject = getJenaNode(nuxStmt.getSubject()); com.hp.hpl.jena.graph.Node predicate = getJenaNode(nuxStmt.getPredicate()); com.hp.hpl.jena.graph.Node object = getJenaNode(nuxStmt.getObject()); Triple jenaTriple = Triple.create(subject, predicate, object); com.hp.hpl.jena.rdf.model.Statement jenaStmt = graph.asStatement(jenaTriple); graph.remove(jenaStmt); // remove properties RSIterator it = graph.listReifiedStatements(jenaStmt); while (it.hasNext()) { ReifiedStatement rs = it.nextRS(); rs.removeProperties(); } // remove quadlets graph.removeAllReifications(jenaStmt); // graph.removeReification(reifiedStmt); } } finally { if (graph != null) { graph.leaveCriticalSection(); } if (graphConnection != null) { graphConnection.close(); } } } @Override public List<Statement> getStatements() { Model graph = null; GraphConnection graphConnection = null; try { graphConnection = openGraph(); graph = graphConnection.getGraph(); graph.enterCriticalSection(Lock.READ); StmtIterator it = graph.listStatements(); return getNXRelationsStatements(graph, it.toList()); } finally { if (graph != null) { graph.leaveCriticalSection(); } if (graphConnection != null) { graphConnection.close(); } } } @Override public List<Statement> getStatements(Node subject, Node predicate, Node object) { return getStatements(new StatementImpl(subject, predicate, object)); } @Override public List<Statement> getStatements(Statement statement) { Model graph = null; GraphConnection graphConnection = null; try { graphConnection = openGraph(); graph = graphConnection.getGraph(); graph.enterCriticalSection(Lock.READ); SimpleSelector selector = getJenaSelector(graph, statement); StmtIterator it = graph.listStatements(selector); return getNXRelationsStatements(graph, it.toList()); } finally { if (graph != null) { graph.leaveCriticalSection(); } if (graphConnection != null) { graphConnection.close(); } } } @Override public List<Node> getSubjects(Node predicate, Node object) { Model graph = null; GraphConnection graphConnection = null; try { graphConnection = openGraph(); graph = graphConnection.getGraph(); graph.enterCriticalSection(Lock.READ); SimpleSelector selector = getJenaSelector(graph, new StatementImpl(null, predicate, object)); ResIterator it = graph.listSubjectsWithProperty(selector.getPredicate(), selector.getObject()); List<Node> res = new ArrayList<Node>(); while (it.hasNext()) { res.add(getNXRelationsNode(it.nextResource().asNode())); } return res; } finally { if (graph != null) { graph.leaveCriticalSection(); } if (graphConnection != null) { graphConnection.close(); } } } @Override public List<Node> getPredicates(Node subject, Node object) { Model graph = null; GraphConnection graphConnection = null; try { graphConnection = openGraph(); graph = graphConnection.getGraph(); graph.enterCriticalSection(Lock.READ); SimpleSelector selector = getJenaSelector(graph, new StatementImpl(subject, null, object)); StmtIterator it = graph.listStatements(selector); List<Statement> statements = getNXRelationsStatements(graph, it.toList()); List<Node> res = new ArrayList<Node>(); for (Statement stmt : statements) { Node predicate = stmt.getPredicate(); if (!res.contains(predicate)) { // remove duplicates res.add(predicate); } } return res; } finally { if (graph != null) { graph.leaveCriticalSection(); } if (graphConnection != null) { graphConnection.close(); } } } @Override public List<Node> getObjects(Node subject, Node predicate) { Model graph = null; GraphConnection graphConnection = null; try { graphConnection = openGraph(); graph = graphConnection.getGraph(); graph.enterCriticalSection(Lock.READ); SimpleSelector selector = getJenaSelector(graph, new StatementImpl(subject, predicate, null)); NodeIterator it = graph.listObjectsOfProperty(selector.getSubject(), selector.getPredicate()); List<Node> res = new ArrayList<Node>(); while (it.hasNext()) { res.add(getNXRelationsNode(it.nextNode().asNode())); } return res; } finally { if (graph != null) { graph.leaveCriticalSection(); } if (graphConnection != null) { graphConnection.close(); } } } @Override public boolean hasStatement(Statement statement) { if (statement == null) { return false; } Model graph = null; GraphConnection graphConnection = null; try { graphConnection = openGraph(); graph = graphConnection.getGraph(); graph.enterCriticalSection(Lock.READ); SimpleSelector selector = getJenaSelector(graph, statement); return graph.contains(selector.getSubject(), selector.getPredicate(), selector.getObject()); } finally { if (graph != null) { graph.leaveCriticalSection(); } if (graphConnection != null) { graphConnection.close(); } } } @Override public boolean hasResource(Resource resource) { if (resource == null) { return false; } Model graph = null; GraphConnection graphConnection = null; try { graphConnection = openGraph(); graph = graphConnection.getGraph(); graph.enterCriticalSection(Lock.READ); com.hp.hpl.jena.graph.Node jenaNodeInst = getJenaNode(resource); RDFNode jenaNode = graph.asRDFNode(jenaNodeInst); return graph.containsResource(jenaNode); } finally { if (graph != null) { graph.leaveCriticalSection(); } if (graphConnection != null) { graphConnection.close(); } } } /** * Returns the number of statements in the graph. * <p> * XXX AT: this size may not be equal to the number of statements retrieved via getStatements() because it counts * each statement property. * * @return integer number of statements in the graph */ @Override public Long size() { Model graph = null; GraphConnection graphConnection = null; try { graphConnection = openGraph(); graph = graphConnection.getGraph(); graph.enterCriticalSection(Lock.READ); return graph.size(); } finally { if (graph != null) { graph.leaveCriticalSection(); } if (graphConnection != null) { graphConnection.close(); } } } @Override public void clear() { Model graph = null; GraphConnection graphConnection = null; try { graphConnection = openGraph(); graph = graphConnection.getGraph(); graph.enterCriticalSection(Lock.READ); graph.removeAll(); // XXX AT: remove reification quadlets explicitly RSIterator it = graph.listReifiedStatements(); List<ReifiedStatement> rss = new ArrayList<ReifiedStatement>(); while (it.hasNext()) { rss.add(it.nextRS()); } for (ReifiedStatement rs : rss) { graph.removeReification(rs); } } finally { if (graph != null) { graph.leaveCriticalSection(); } if (graphConnection != null) { graphConnection.close(); } } } @Override public QueryResult query(String queryString, String language, String baseURI) { Model graph = null; GraphConnection graphConnection = null; QueryResult res = null; QueryExecution qe = null; try { graphConnection = openGraph(); graph = graphConnection.getGraph(); graph.enterCriticalSection(Lock.READ); log.debug(String.format("Running query %s", queryString)); // XXX AT: ignore language for now if (language != null && !language.equals("sparql")) { log.warn(String.format("Unknown language %s for query, using SPARQL", language)); } Query query = QueryFactory.create(queryString); query.setBaseURI(baseURI); qe = QueryExecutionFactory.create(query, graph); res = new QueryResultImpl(0, new ArrayList<String>(), new ArrayList<Map<String, Node>>()); ResultSet jenaResults = qe.execSelect(); Integer count = 0; List<String> variableNames = jenaResults.getResultVars(); List<Map<String, Node>> nuxResults = new ArrayList<Map<String, Node>>(); while (jenaResults.hasNext()) { QuerySolution soln = jenaResults.nextSolution(); Map<String, Node> nuxSol = new HashMap<String, Node>(); for (String varName : variableNames) { RDFNode x = soln.get(varName); nuxSol.put(varName, getNXRelationsNode(x.asNode())); } nuxResults.add(nuxSol); count++; } res = new QueryResultImpl(count, variableNames, nuxResults); } finally { if (qe != null) { // Important - free up resources used running the query qe.close(); } if (graph != null) { graph.leaveCriticalSection(); } if (graphConnection != null) { graphConnection.close(); } } return res; } @Override public int queryCount(String queryString, String language, String baseURI) { return query(queryString, language, baseURI).getResults().size(); } @Override public boolean read(InputStream in, String lang, String base) { // XXX AT: maybe update namespaces in case some new appeared Model graph = null; GraphConnection graphConnection = null; try { graphConnection = openGraph(); graph = graphConnection.getGraph(); graph.enterCriticalSection(Lock.READ); graph.read(in, base, lang); // default to true return true; } finally { if (graph != null) { graph.leaveCriticalSection(); } if (graphConnection != null) { graphConnection.close(); } } } @Override public boolean read(String path, String lang, String base) { // XXX AT: maybe update namespaces in case some new appeared InputStream in = null; try { in = new FileInputStream(path); return read(in, lang, base); } catch (IOException e) { throw new RuntimeException(e); } finally { if (in != null) { try { in.close(); } catch (IOException e) { } } } } @Override public boolean write(OutputStream out, String lang, String base) { Model graph = null; GraphConnection graphConnection = null; try { graphConnection = openGraph(); graph = graphConnection.getGraph(); graph.enterCriticalSection(Lock.WRITE); graph.write(out, lang, base); // default to true return true; } finally { if (graph != null) { graph.leaveCriticalSection(); } if (graphConnection != null) { graphConnection.close(); } } } @Override public boolean write(String path, String lang, String base) { OutputStream out = null; try { File file = new File(path); out = new FileOutputStream(file); return write(out, lang, base); } catch (IOException e) { throw new RuntimeException(e); } finally { if (out != null) { try { out.close(); } catch (IOException e) { } } } } } /** * This invocation handler is designed to wrap a normal connection but avoid all calls to * <ul> * <li>{@link Connection#commit}</li> * <li>{@link Connection#setAutoCommit}</li> * </ul> * <p> * We have to do this because Jena calls these methods without regard to the fact that the connection may be managed by * an external transaction. * * @author Florent Guillaume */ class ConnectionFixInvocationHandler implements InvocationHandler { private final Connection connection; ConnectionFixInvocationHandler(Connection connection) { this.connection = connection; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { final String name = method.getName(); if (name.equals("commit")) { return null; } else if (name.equals("setAutoCommit")) { return null; } else { try { return method.invoke(connection, args); } catch (InvocationTargetException e) { throw e.getCause(); } } } }