Return-Path: X-Original-To: apmail-clerezza-commits-archive@www.apache.org Delivered-To: apmail-clerezza-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 1217A11DC8 for ; Fri, 11 Apr 2014 14:59:03 +0000 (UTC) Received: (qmail 49339 invoked by uid 500); 11 Apr 2014 14:59:02 -0000 Delivered-To: apmail-clerezza-commits-archive@clerezza.apache.org Received: (qmail 49298 invoked by uid 500); 11 Apr 2014 14:58:56 -0000 Mailing-List: contact commits-help@clerezza.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@clerezza.apache.org Delivered-To: mailing list commits@clerezza.apache.org Received: (qmail 49256 invoked by uid 99); 11 Apr 2014 14:58:53 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 11 Apr 2014 14:58:53 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id A424D98ABD6; Fri, 11 Apr 2014 14:58:52 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: enridaga@apache.org To: commits@clerezza.apache.org Date: Fri, 11 Apr 2014 14:58:52 -0000 Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: [1/2] git commit: CLEREZZA-906 Adding SPARQL query support to the virtuoso storage provider Repository: clerezza Updated Branches: refs/heads/master 59371d757 -> 824f09fa0 CLEREZZA-906 Adding SPARQL query support to the virtuoso storage provider Project: http://git-wip-us.apache.org/repos/asf/clerezza/repo Commit: http://git-wip-us.apache.org/repos/asf/clerezza/commit/e130ccce Tree: http://git-wip-us.apache.org/repos/asf/clerezza/tree/e130ccce Diff: http://git-wip-us.apache.org/repos/asf/clerezza/diff/e130ccce Branch: refs/heads/master Commit: e130cccefb9b8c6abb647082020f47f5b9bdc1bb Parents: 59371d7 Author: enridaga Authored: Fri Apr 11 15:57:27 2014 +0100 Committer: enridaga Committed: Fri Apr 11 15:57:27 2014 +0100 ---------------------------------------------------------------------- .../rdf/virtuoso/storage/access/DataAccess.java | 419 ++++++++++++++----- .../access/VirtuosoWeightedProvider.java | 15 +- .../virtuoso/storage/access/DataAccessTest.java | 44 +- 3 files changed, 368 insertions(+), 110 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/clerezza/blob/e130ccce/rdf.virtuoso.storage/src/main/java/org/apache/clerezza/rdf/virtuoso/storage/access/DataAccess.java ---------------------------------------------------------------------- diff --git a/rdf.virtuoso.storage/src/main/java/org/apache/clerezza/rdf/virtuoso/storage/access/DataAccess.java b/rdf.virtuoso.storage/src/main/java/org/apache/clerezza/rdf/virtuoso/storage/access/DataAccess.java index 5b41318..ab0c32a 100644 --- a/rdf.virtuoso.storage/src/main/java/org/apache/clerezza/rdf/virtuoso/storage/access/DataAccess.java +++ b/rdf.virtuoso.storage/src/main/java/org/apache/clerezza/rdf/virtuoso/storage/access/DataAccess.java @@ -27,10 +27,12 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import javax.sql.PooledConnection; @@ -44,8 +46,11 @@ import org.apache.clerezza.rdf.core.Triple; import org.apache.clerezza.rdf.core.TypedLiteral; import org.apache.clerezza.rdf.core.UriRef; import org.apache.clerezza.rdf.core.impl.PlainLiteralImpl; +import org.apache.clerezza.rdf.core.impl.SimpleGraph; import org.apache.clerezza.rdf.core.impl.TripleImpl; import org.apache.clerezza.rdf.core.impl.TypedLiteralImpl; +import org.apache.clerezza.rdf.core.sparql.SolutionMapping; +import org.apache.clerezza.rdf.core.sparql.query.Variable; import org.apache.clerezza.rdf.virtuoso.storage.VirtuosoBNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -581,7 +586,7 @@ public class DataAccess { } /** - * Builds a clerezza Triple from Virtuoso result types + * Builds a clerezza Triple from a Virtuoso result types * */ private class TripleBuilder { @@ -599,112 +604,10 @@ public class DataAccess { this.o = o; } - private NonLiteral buildSubject() { - if (s instanceof VirtuosoExtendedString) { - VirtuosoExtendedString vs = (VirtuosoExtendedString) s; - if (vs.iriType == VirtuosoExtendedString.IRI - && (vs.strType & 0x01) == 0x01) { - // Subject is IRI - return new UriRef(vs.str); - } else if (vs.iriType == VirtuosoExtendedString.BNODE) { - return DataAccess.this.toBNode(vs.str); - } else { - // !Cannot happen - throw new IllegalStateException( - "Subject must be an IRI or a BNODE"); - } - } else { - throw new IllegalStateException( - "Subject must be an instance of VirtuosoExtendedString"); - } - } - - private UriRef buildPredicate() { - if (p instanceof VirtuosoExtendedString) { - VirtuosoExtendedString vs = (VirtuosoExtendedString) p; - if (vs.iriType == VirtuosoExtendedString.IRI - && (vs.strType & 0x01) == 0x01) { - // Subject is IRI - return new UriRef(vs.str); - } else { - // !Cannot happen - throw new IllegalStateException("Predicate must be an IRI "); - } - } else { - throw new IllegalStateException("Predicate must be an IRI"); - } - } - - Resource buildObject() { - if (o instanceof VirtuosoExtendedString) { - // In case is IRI - VirtuosoExtendedString vs = (VirtuosoExtendedString) o; - if (vs.iriType == VirtuosoExtendedString.IRI - && (vs.strType & 0x01) == 0x01) { - // Is IRI - return new UriRef(vs.str); - } else if (vs.iriType == VirtuosoExtendedString.BNODE) { - // - return DataAccess.this.toBNode(vs.str); - } else { - // Is a plain literal - return new PlainLiteralImpl(vs.str); - } - } else if (o instanceof VirtuosoRdfBox) { - // In case is typed literal - VirtuosoRdfBox rb = (VirtuosoRdfBox) o; - - String value; - if (rb.rb_box.getClass().isAssignableFrom(String.class)) { - value = (String) rb.rb_box; - String lang = rb.getLang(); - String type = rb.getType(); - if (type == null) { - Language language = lang == null ? null : new Language( - lang); - return new PlainLiteralImpl(value, language); - } else { - return new TypedLiteralImpl(value, new UriRef(type)); - } - } else if (rb.rb_box instanceof VirtuosoExtendedString) { - VirtuosoExtendedString vs = (VirtuosoExtendedString) rb.rb_box; - - if (vs.iriType == VirtuosoExtendedString.IRI - && (vs.strType & 0x01) == 0x01) { - // Is IRI - return new UriRef(vs.str); - } else if (vs.iriType == VirtuosoExtendedString.BNODE) { - // - return DataAccess.this.toBNode(vs.str); - } else { - String type = rb.getType(); - if (type == null) { - String lang = rb.getLang(); - if (lang != null) { - return new PlainLiteralImpl(vs.str, - new Language(lang)); - } - // Is a plain literal - return new PlainLiteralImpl(vs.str); - } else { - return new TypedLiteralImpl(vs.str, - new UriRef(type)); - } - } - } - } else if (o == null) { - // Raise an exception - throw new IllegalStateException("Object cannot be NULL!"); - } - - // FIXME (not clear this...) - return new PlainLiteralImpl(o.toString()); - } - public Triple build() { logger.debug("TripleBuilder.build()"); - return new TripleImpl(buildSubject(), buildPredicate(), - buildObject()); + return new TripleImpl(buildSubject(this.s), buildPredicate(this.p), + buildObject(this.o)); } } @@ -873,5 +776,311 @@ public class DataAccess { "subject must be BNode or UriRef"); } } + + /** + * From a Virtuoso object to NonLiteral + * + * @param s + * @return + */ + private NonLiteral buildSubject(Object s) { + if (s instanceof VirtuosoExtendedString) { + VirtuosoExtendedString vs = (VirtuosoExtendedString) s; + if (vs.iriType == VirtuosoExtendedString.IRI + && (vs.strType & 0x01) == 0x01) { + // Subject is IRI + return new UriRef(vs.str); + } else if (vs.iriType == VirtuosoExtendedString.BNODE) { + return DataAccess.this.toBNode(vs.str); + } else { + // !Cannot happen + throw new IllegalStateException( + "Subject must be an IRI or a BNODE"); + } + } else { + throw new IllegalStateException( + "Subject must be an instance of VirtuosoExtendedString"); + } + } + + private UriRef buildPredicate(Object p) { + if (p instanceof VirtuosoExtendedString) { + VirtuosoExtendedString vs = (VirtuosoExtendedString) p; + if (vs.iriType == VirtuosoExtendedString.IRI + && (vs.strType & 0x01) == 0x01) { + // Subject is IRI + return new UriRef(vs.str); + } else { + // !Cannot happen + throw new IllegalStateException("Predicate must be an IRI "); + } + } else { + throw new IllegalStateException("Predicate must be an IRI"); + } + } + + private Resource buildObject(Object o) { + if (o instanceof VirtuosoExtendedString) { + // In case is IRI + VirtuosoExtendedString vs = (VirtuosoExtendedString) o; + if (vs.iriType == VirtuosoExtendedString.IRI + && (vs.strType & 0x01) == 0x01) { + // Is IRI + return new UriRef(vs.str); + } else if (vs.iriType == VirtuosoExtendedString.BNODE) { + // + return DataAccess.this.toBNode(vs.str); + } else { + // Is a plain literal + return new PlainLiteralImpl(vs.str); + } + } else if (o instanceof VirtuosoRdfBox) { + // In case is typed literal + VirtuosoRdfBox rb = (VirtuosoRdfBox) o; + + String value; + if (rb.rb_box.getClass().isAssignableFrom(String.class)) { + value = (String) rb.rb_box; + String lang = rb.getLang(); + String type = rb.getType(); + if (type == null) { + Language language = lang == null ? null : new Language( + lang); + return new PlainLiteralImpl(value, language); + } else { + return new TypedLiteralImpl(value, new UriRef(type)); + } + } else if (rb.rb_box instanceof VirtuosoExtendedString) { + VirtuosoExtendedString vs = (VirtuosoExtendedString) rb.rb_box; + + if (vs.iriType == VirtuosoExtendedString.IRI + && (vs.strType & 0x01) == 0x01) { + // Is IRI + return new UriRef(vs.str); + } else if (vs.iriType == VirtuosoExtendedString.BNODE) { + // + return DataAccess.this.toBNode(vs.str); + } else { + String type = rb.getType(); + if (type == null) { + String lang = rb.getLang(); + if (lang != null) { + return new PlainLiteralImpl(vs.str, + new Language(lang)); + } + // Is a plain literal + return new PlainLiteralImpl(vs.str); + } else { + return new TypedLiteralImpl(vs.str, + new UriRef(type)); + } + } + } + } else if (o == null) { + // Raise an exception + throw new IllegalStateException("Object cannot be NULL!"); + } + + // FIXME (not clear this...) + return new PlainLiteralImpl(o.toString()); + } + + private Resource objectToResource(Object o){ + return buildObject(o); + } + + /** + * This is to execute SPARQL queries. + * + * @param query + * @param defaultGraphUri + * @return + */ + public Object executeSparqlQuery(String query, UriRef defaultGraphUri) { + Connection connection = null; + ResultSet rs = null; + Statement st = null; + logger.debug("executeSparqlQuery(String {}, UriRef {})", query, defaultGraphUri); + Exception e = null; + + StringBuilder qb = new StringBuilder(); + qb.append("SPARQL "); + if(defaultGraphUri != null){ + qb.append("DEFINE input:default-graph-uri <"); + qb.append(defaultGraphUri.getUnicodeString()); + qb.append(">"); + qb.append("\n"); + } + qb.append(query); + Object returnThis = null; + try { + connection = getConnection(); + String sql = qb.toString(); + logger.debug("Executing SQL: {}", sql); + st = connection.createStatement(); + st.execute(sql); + rs = st.getResultSet(); + // ASK :: Boolean + if (rs.getMetaData().getColumnCount() == 1 + && rs.getMetaData().getColumnType(1) == 4) { + rs.next(); + returnThis = rs.getBoolean(1); + } else + // CONSTRCUT/DESCRIBE :: TripleCollection + if (rs.getMetaData().getColumnCount() == 3 + && rs.getMetaData().getColumnType(1) == 12 + && rs.getMetaData().getColumnType(2) == 12 + && rs.getMetaData().getColumnType(3) == 1111) { + final List lt = new ArrayList(); + while (rs.next()) { + lt.add(new TripleBuilder(rs.getObject(1), rs.getObject(2), + rs.getObject(3)).build()); + } + returnThis = new SimpleGraph(lt.iterator()); + } else { + // SELECT (anything else?) + returnThis = new SparqlResultSetWrapper(rs); + } + } catch (VirtuosoException ve) { + logger.error("A virtuoso SQL exception occurred."); + e = ve; + } catch (SQLException se) { + logger.error("An SQL exception occurred."); + e = se; + } finally { + close(rs, st, connection); + } + if (e != null) { + throw new RuntimeException(e); + } + + return returnThis; + } + + /** + * To wrap a sparql result set + * @author enridaga + * + */ + private class SparqlResultSetWrapper implements org.apache.clerezza.rdf.core.sparql.ResultSet { + + private final List resultVars; + private Iterator iterator; + + SparqlResultSetWrapper(final ResultSet jdbcResultSet) throws SQLException { + + resultVars = new ArrayList(); + for(int x = 1; x < jdbcResultSet.getMetaData().getColumnCount() + 1; x++){ + resultVars.add(jdbcResultSet.getMetaData().getColumnName(x)); + } + + final List solutions = new ArrayList(); + while (jdbcResultSet.next()) { + RSSolutionMapping sm = new RSSolutionMapping(); + for(String column : resultVars){ + sm.put(new Variable(column), objectToResource(jdbcResultSet.getObject(column))); + } + solutions.add(sm); + } + iterator = solutions.iterator(); + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public SolutionMapping next() { + return iterator.next(); + } + + @Override + public void remove() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List getResultVars() { + return resultVars; + } + } + + /** + * This is a utility class + * + * @author enridaga + * + */ + private class RSSolutionMapping implements SolutionMapping { + + private Map map; + + @Override + public int size() { + return map.size(); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return map.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return map.containsValue(value); + } + + @Override + public Resource get(Object key) { + return map.get(key); + } + + @Override + public Resource put(Variable key, Resource value) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Resource remove(Object key) { + return map.remove(key); + } + + @Override + public void putAll(Map m) { + map.putAll(m); + } + + @Override + public void clear() { + map.clear(); + } + + @Override + public Set keySet() { + return map.keySet(); + } + + @Override + public Collection values() { + return map.values(); + } + + @Override + public Set> entrySet() { + return map.entrySet(); + } + + @Override + public Resource get(String name) { + return map.get(new Variable(name)); + } + } } http://git-wip-us.apache.org/repos/asf/clerezza/blob/e130ccce/rdf.virtuoso.storage/src/main/java/org/apache/clerezza/rdf/virtuoso/storage/access/VirtuosoWeightedProvider.java ---------------------------------------------------------------------- diff --git a/rdf.virtuoso.storage/src/main/java/org/apache/clerezza/rdf/virtuoso/storage/access/VirtuosoWeightedProvider.java b/rdf.virtuoso.storage/src/main/java/org/apache/clerezza/rdf/virtuoso/storage/access/VirtuosoWeightedProvider.java index e188343..178f9c1 100644 --- a/rdf.virtuoso.storage/src/main/java/org/apache/clerezza/rdf/virtuoso/storage/access/VirtuosoWeightedProvider.java +++ b/rdf.virtuoso.storage/src/main/java/org/apache/clerezza/rdf/virtuoso/storage/access/VirtuosoWeightedProvider.java @@ -83,7 +83,7 @@ import virtuoso.jdbc4.VirtuosoException; @Property(name = "user", description = "User name"), @Property(name = "weight", intValue = 110, description = "Weight assigned to this provider"), @Property(name = TcManager.GENERAL_PURPOSE_TC, boolValue = true) }) -public class VirtuosoWeightedProvider implements WeightedTcProvider { +public class VirtuosoWeightedProvider implements WeightedTcProvider, QueryableTcProvider { // JDBC driver class (XXX move to DataAccess?) public static final String DRIVER = "virtuoso.jdbc4.Driver"; @@ -123,6 +123,8 @@ public class VirtuosoWeightedProvider implements WeightedTcProvider { private int weight = DEFAULT_WEIGHT; private String charset = "UTF-8"; private String roundrobin = "0"; + + private DataAccess sparqlDataAccess; /** * Creates a new {@link VirtuosoWeightedProvider}. @@ -141,6 +143,7 @@ public class VirtuosoWeightedProvider implements WeightedTcProvider { this.user = jdbcUser; this.pwd = jdbcPassword; initConnectionPoolDataSource(); + this.sparqlDataAccess = createDataAccess(); } private void initConnectionPoolDataSource(){ @@ -270,6 +273,8 @@ public class VirtuosoWeightedProvider implements WeightedTcProvider { pwd = (String) ppwd; initConnectionPoolDataSource(); + // Prepare SPARQL data access + this.sparqlDataAccess = createDataAccess(); // Check connection Connection connection = getConnection(); @@ -947,4 +952,12 @@ public class VirtuosoWeightedProvider implements WeightedTcProvider { logger.debug("setWeight(int {})", weight); this.weight = weight; } + + /** + * Executes a SPARQL query + */ + @Override + public Object executeSparqlQuery(String query, UriRef defaultGraphUri) { + return this.sparqlDataAccess.executeSparqlQuery(query, defaultGraphUri); + } } http://git-wip-us.apache.org/repos/asf/clerezza/blob/e130ccce/rdf.virtuoso.storage/src/test/java/org/apache/clerezza/rdf/virtuoso/storage/access/DataAccessTest.java ---------------------------------------------------------------------- diff --git a/rdf.virtuoso.storage/src/test/java/org/apache/clerezza/rdf/virtuoso/storage/access/DataAccessTest.java b/rdf.virtuoso.storage/src/test/java/org/apache/clerezza/rdf/virtuoso/storage/access/DataAccessTest.java index 5e5146b..3d59fa1 100644 --- a/rdf.virtuoso.storage/src/test/java/org/apache/clerezza/rdf/virtuoso/storage/access/DataAccessTest.java +++ b/rdf.virtuoso.storage/src/test/java/org/apache/clerezza/rdf/virtuoso/storage/access/DataAccessTest.java @@ -39,7 +39,7 @@ import org.slf4j.LoggerFactory; public class DataAccessTest { private static DataAccess da = null; - + private final static String testGraphName = "urn:x-test:DataAccessTest"; static Logger log = LoggerFactory.getLogger(DataAccessTest.class); @BeforeClass @@ -50,18 +50,18 @@ public class DataAccessTest { @Before public void before() throws ClassNotFoundException, SQLException { da = TestUtils.getProvider().createDataAccess(); - da.clearGraph( "urn:x-test:DataAccessTest" ); + da.clearGraph( testGraphName ); } @After public void after() { - da.clearGraph( "urn:x-test:DataAccessTest" ); + da.clearGraph( testGraphName ); da.close(); da = null; } private void testTriple(Triple t){ - String g = "urn:x-test:DataAccessTest"; + String g = testGraphName; da.insertQuad(g, t); Assert.assertTrue(da.filter(g, null, null, null).hasNext()); @@ -101,6 +101,42 @@ public class DataAccessTest { Triple t = new TripleImpl(new UriRef("urn:subject"), new UriRef("urn:predicate"), new BNode()); testTriple(t); } + + @Test + public void testSparqlSelect(){ + Triple t = new TripleImpl(new UriRef("urn:subject"), new UriRef("urn:predicate"), new UriRef("urn:object")); + da.insertQuad(testGraphName, t); + String select = "SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 1"; + da.executeSparqlQuery(select, new UriRef(testGraphName)); + da.executeSparqlQuery(select, null); + } + + @Test + public void testSparqlConstruct(){ + Triple t = new TripleImpl(new UriRef("urn:subject"), new UriRef("urn:predicate"), new UriRef("urn:object")); + da.insertQuad(testGraphName, t); + String select = "CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o } LIMIT 1"; + da.executeSparqlQuery(select, new UriRef(testGraphName)); + da.executeSparqlQuery(select, null); + } + + @Test + public void testSparqlAsk(){ + Triple t = new TripleImpl(new UriRef("urn:subject"), new UriRef("urn:predicate"), new UriRef("urn:object")); + da.insertQuad(testGraphName, t); + String ask = "ASK { [] [] [] }"; + da.executeSparqlQuery(ask, new UriRef(testGraphName)); + da.executeSparqlQuery(ask, null); + } + + @Test + public void testSparqlDescribe(){ + Triple t = new TripleImpl(new UriRef("urn:subject"), new UriRef("urn:predicate"), new UriRef("urn:object")); + da.insertQuad(testGraphName, t); + String describe = "DESCRIBE "; + da.executeSparqlQuery(describe, new UriRef(testGraphName)); + da.executeSparqlQuery(describe, null); + } // @Test // public void testRenew(){