From a0a60cd477841e8322b8e2441c24c96f4a41ddc6 Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Wed, 1 Nov 2023 14:10:54 +0100 Subject: [PATCH 1/6] Avoid lock on graph uri update in rdfServiceSparql --- .../SameAsFilteringRDFServiceFactory.java | 4 + .../rdfservice/impl/RDFServiceImpl.java | 38 +++++-- .../rdfservice/impl/jena/RDFServiceJena.java | 14 --- .../impl/sparql/RDFServiceSparql.java | 103 ++++++++++-------- ...eJenaTest.java => RDFServiceImplTest.java} | 6 +- 5 files changed, 91 insertions(+), 74 deletions(-) rename api/src/test/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/{jena/RDFServiceJenaTest.java => RDFServiceImplTest.java} (91%) diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/SameAsFilteringRDFServiceFactory.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/SameAsFilteringRDFServiceFactory.java index e585c54aaf..82f575f601 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/SameAsFilteringRDFServiceFactory.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/SameAsFilteringRDFServiceFactory.java @@ -316,6 +316,10 @@ public void close() { s.close(); } + @Override + protected void rebuildGraphUris() { + } + } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java index 92c7329ab8..8e0767358f 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java @@ -9,9 +9,17 @@ import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener; +import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet; +import edu.cornell.mannlib.vitro.webapp.rdfservice.ModelChange; +import edu.cornell.mannlib.vitro.webapp.rdfservice.ModelChange.Operation; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; +import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer; +import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.apache.jena.atlas.io.StringWriterI; import org.apache.jena.graph.Node; import org.apache.jena.graph.NodeFactory; @@ -32,16 +40,6 @@ import org.apache.jena.riot.out.NodeFormatterTTL; import org.apache.jena.vocabulary.RDF; -import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener; -import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet; -import edu.cornell.mannlib.vitro.webapp.rdfservice.ModelChange; -import edu.cornell.mannlib.vitro.webapp.rdfservice.ModelChange.Operation; -import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; -import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; -import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer; -import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString; - public abstract class RDFServiceImpl implements RDFService { private static final Log log = LogFactory.getLog(RDFServiceImpl.class); @@ -49,6 +47,9 @@ public abstract class RDFServiceImpl implements RDFService { protected String defaultWriteGraphURI; protected List registeredListeners = new CopyOnWriteArrayList(); protected List registeredJenaListeners = new CopyOnWriteArrayList(); + protected final List graphURIs = new CopyOnWriteArrayList(); + protected volatile boolean rebuildGraphURICache = true; + protected volatile boolean isRebuildGraphURICacheRunning = false; @Override public void newIndividual(String individualURI, @@ -87,7 +88,20 @@ public void newIndividual(String individualURI, } } - @Override + /** + * Get a list of all the graph URIs in the RDF store. + */ + @Override + public List getGraphURIs() throws RDFServiceException { + if (rebuildGraphURICache && !isRebuildGraphURICacheRunning) { + rebuildGraphUris(); + } + return graphURIs; + } + + protected abstract void rebuildGraphUris(); + + @Override public String getDefaultWriteGraphURI() throws RDFServiceException { return defaultWriteGraphURI; } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java index 84405d1696..32658a8ead 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java @@ -9,9 +9,7 @@ import java.io.OutputStream; import java.util.HashSet; import java.util.Iterator; -import java.util.List; import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.dao.jena.DatasetWrapper; @@ -58,10 +56,6 @@ public abstract class RDFServiceJena extends RDFServiceImpl implements RDFServic protected abstract DatasetWrapper getDatasetWrapper(); - protected volatile boolean rebuildGraphURICache = true; - protected volatile boolean isRebuildGraphURICacheRunning = false; - protected final List graphURIs = new CopyOnWriteArrayList(); - @Override public abstract boolean changeSetUpdate(ChangeSet changeSet) throws RDFServiceException; @@ -312,14 +306,6 @@ public boolean sparqlAskQuery(String query) throws RDFServiceException { } } - @Override - public List getGraphURIs() throws RDFServiceException { - if (rebuildGraphURICache && !isRebuildGraphURICacheRunning) { - rebuildGraphUris(); - } - return graphURIs; - } - protected void rebuildGraphUris() { Thread thread = new VitroBackgroundThread(new Runnable() { public void run() { diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java index c3fec0c1b0..664e3ae774 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java @@ -11,11 +11,29 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; +import edu.cornell.mannlib.vitro.webapp.dao.jena.JenaModelUtils; +import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceDataset; +import edu.cornell.mannlib.vitro.webapp.dao.jena.SparqlGraph; +import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener; +import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet; +import edu.cornell.mannlib.vitro.webapp.rdfservice.ModelChange; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; +import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer; +import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.ChangeSetImpl; +import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceImpl; +import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils; +import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena.RDFServiceJena; +import edu.cornell.mannlib.vitro.webapp.utils.http.HttpClientFactory; +import edu.cornell.mannlib.vitro.webapp.utils.sparql.ResultSetIterators.ResultSetQuadsIterator; +import edu.cornell.mannlib.vitro.webapp.utils.sparql.ResultSetIterators.ResultSetTriplesIterator; +import edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -56,22 +74,6 @@ import org.apache.jena.riot.RDFDataMgr; import org.apache.jena.sparql.core.Quad; -import edu.cornell.mannlib.vitro.webapp.dao.jena.JenaModelUtils; -import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceDataset; -import edu.cornell.mannlib.vitro.webapp.dao.jena.SparqlGraph; -import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener; -import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet; -import edu.cornell.mannlib.vitro.webapp.rdfservice.ModelChange; -import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; -import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; -import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer; -import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.ChangeSetImpl; -import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceImpl; -import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils; -import edu.cornell.mannlib.vitro.webapp.utils.http.HttpClientFactory; -import edu.cornell.mannlib.vitro.webapp.utils.sparql.ResultSetIterators.ResultSetQuadsIterator; -import edu.cornell.mannlib.vitro.webapp.utils.sparql.ResultSetIterators.ResultSetTriplesIterator; - /* * API to write, read, and update Vitro's RDF store, with support * to allow listening, logging and auditing. @@ -89,8 +91,6 @@ public class RDFServiceSparql extends RDFServiceImpl implements RDFService { protected HttpClient httpClient; protected boolean rebuildGraphURICache = true; - private List graphURIs = null; - /** * Returns an RDFService for a remote repository * @param readEndpointURI - URI of the read SPARQL endpoint for the knowledge base @@ -384,32 +384,45 @@ public boolean sparqlAskQuery(String queryStr) throws RDFServiceException { } } - /** - * Get a list of all the graph URIs in the RDF store. - */ - @Override - public List getGraphURIs() throws RDFServiceException { - if (graphURIs == null || rebuildGraphURICache) { - graphURIs = getGraphURIsFromSparqlQuery(); - rebuildGraphURICache = false; - } - return graphURIs; - } - - private List getGraphURIsFromSparqlQuery() throws RDFServiceException { - String fastJenaQuery = "SELECT DISTINCT ?g WHERE { GRAPH ?g {} } ORDER BY ?g"; - String standardQuery = "SELECT DISTINCT ?g WHERE { GRAPH ?g { ?s ?p ?o } }"; - List graphURIs = new ArrayList(); - try { - graphURIs = getGraphURIsFromSparqlQuery(fastJenaQuery); - } catch (Exception e) { - log.debug("Unable to use non-standard ARQ query for graph list", e); - } - if (graphURIs.isEmpty()) { - graphURIs = getGraphURIsFromSparqlQuery(standardQuery); - Collections.sort(graphURIs); - } - return graphURIs; + protected void rebuildGraphUris() { + Thread thread = new VitroBackgroundThread(new Runnable() { + public void run() { + synchronized (RDFServiceJena.class) { + if (rebuildGraphURICache) { + try { + isRebuildGraphURICacheRunning = true; + Set newGraphUris = new HashSet<>(); + try { + String fastJenaQuery = "SELECT DISTINCT ?g WHERE { GRAPH ?g {} } ORDER BY ?g"; + newGraphUris.addAll(getGraphURIsFromSparqlQuery(fastJenaQuery)); + } catch (Exception e) { + log.debug("Unable to use non-standard ARQ query for graph list", e); + } + if (graphURIs.isEmpty()) { + String standardQuery = "SELECT DISTINCT ?g WHERE { GRAPH ?g { ?s ?p ?o } }"; + newGraphUris.addAll(getGraphURIsFromSparqlQuery(standardQuery)); + } + Set oldGraphUris = new HashSet(graphURIs); + if (newGraphUris.equals(oldGraphUris)) { + return; + } + Set removedGraphUris = new HashSet(oldGraphUris); + removedGraphUris.removeAll(newGraphUris); + graphURIs.removeAll(removedGraphUris); + Set addedGraphUris = new HashSet(newGraphUris); + addedGraphUris.removeAll(oldGraphUris); + graphURIs.addAll(addedGraphUris); + } catch (Exception e) { + log.error(e, e); + } finally { + isRebuildGraphURICacheRunning = false; + rebuildGraphURICache = false; + } + } + } + } + }, "Rebuild graphURI cache thread"); + thread.start(); } private List getGraphURIsFromSparqlQuery(String queryString) throws RDFServiceException { diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJenaTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImplTest.java similarity index 91% rename from api/src/test/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJenaTest.java rename to api/src/test/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImplTest.java index f789ee919d..41a4e2a2d7 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJenaTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImplTest.java @@ -1,4 +1,4 @@ -package edu.cornell.mannlib.vitro.webapp.rdfservice.impl.jena; +package edu.cornell.mannlib.vitro.webapp.rdfservice.impl; import java.util.Iterator; import java.util.List; @@ -11,7 +11,7 @@ import org.apache.jena.rdf.model.Model; import org.junit.Test; -public class RDFServiceJenaTest { +public class RDFServiceImplTest { @Test public void getConcurrentGraphUrisTest() throws RDFServiceException, InterruptedException { @@ -20,7 +20,7 @@ public void getConcurrentGraphUrisTest() throws RDFServiceException, Interrupted testDataSet.addNamedModel("test:init1", m1); Model m2 = VitroModelFactory.createModel(); testDataSet.addNamedModel("test:init2", m2); - RDFServiceJena rdfService = new RDFServiceModel(testDataSet); + RDFServiceImpl rdfService = new RDFServiceModel(testDataSet); rdfService.getGraphURIs(); long i = 0; while (rdfService.rebuildGraphURICache) { From 600658138bd0832742f432b22d09818c6d53562e Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Wed, 1 Nov 2023 14:28:05 +0100 Subject: [PATCH 2/6] delete duplicate variable initialization --- .../vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java | 1 - 1 file changed, 1 deletion(-) diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java index 664e3ae774..039e0dbc9f 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java @@ -90,7 +90,6 @@ public class RDFServiceSparql extends RDFServiceImpl implements RDFService { protected HttpClient httpClient; - protected boolean rebuildGraphURICache = true; /** * Returns an RDFService for a remote repository * @param readEndpointURI - URI of the read SPARQL endpoint for the knowledge base From 7b6f2e2bc3271ad1c8ad886b958bbd2eae7bfa04 Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Fri, 3 Nov 2023 09:58:03 +0100 Subject: [PATCH 3/6] fix identation --- .../rdfservice/impl/RDFServiceImpl.java | 30 ++++---- .../impl/sparql/RDFServiceSparql.java | 76 +++++++++---------- 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java index 8e0767358f..0a9a48dda8 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java @@ -48,8 +48,8 @@ public abstract class RDFServiceImpl implements RDFService { protected List registeredListeners = new CopyOnWriteArrayList(); protected List registeredJenaListeners = new CopyOnWriteArrayList(); protected final List graphURIs = new CopyOnWriteArrayList(); - protected volatile boolean rebuildGraphURICache = true; - protected volatile boolean isRebuildGraphURICacheRunning = false; + protected volatile boolean rebuildGraphURICache = true; + protected volatile boolean isRebuildGraphURICacheRunning = false; @Override public void newIndividual(String individualURI, @@ -88,22 +88,22 @@ public void newIndividual(String individualURI, } } - /** - * Get a list of all the graph URIs in the RDF store. - */ - @Override - public List getGraphURIs() throws RDFServiceException { - if (rebuildGraphURICache && !isRebuildGraphURICacheRunning) { - rebuildGraphUris(); - } - return graphURIs; - } - + /** + * Get a list of all the graph URIs in the RDF store. + */ + @Override + public List getGraphURIs() throws RDFServiceException { + if (rebuildGraphURICache && !isRebuildGraphURICacheRunning) { + rebuildGraphUris(); + } + return graphURIs; + } + protected abstract void rebuildGraphUris(); - @Override + @Override public String getDefaultWriteGraphURI() throws RDFServiceException { - return defaultWriteGraphURI; + return defaultWriteGraphURI; } @Override diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java index 039e0dbc9f..525ea669e7 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java @@ -384,44 +384,44 @@ public boolean sparqlAskQuery(String queryStr) throws RDFServiceException { } protected void rebuildGraphUris() { - Thread thread = new VitroBackgroundThread(new Runnable() { - public void run() { - synchronized (RDFServiceJena.class) { - if (rebuildGraphURICache) { - try { - isRebuildGraphURICacheRunning = true; - Set newGraphUris = new HashSet<>(); - try { - String fastJenaQuery = "SELECT DISTINCT ?g WHERE { GRAPH ?g {} } ORDER BY ?g"; - newGraphUris.addAll(getGraphURIsFromSparqlQuery(fastJenaQuery)); - } catch (Exception e) { - log.debug("Unable to use non-standard ARQ query for graph list", e); - } - if (graphURIs.isEmpty()) { - String standardQuery = "SELECT DISTINCT ?g WHERE { GRAPH ?g { ?s ?p ?o } }"; - newGraphUris.addAll(getGraphURIsFromSparqlQuery(standardQuery)); - } - Set oldGraphUris = new HashSet(graphURIs); - if (newGraphUris.equals(oldGraphUris)) { - return; - } - Set removedGraphUris = new HashSet(oldGraphUris); - removedGraphUris.removeAll(newGraphUris); - graphURIs.removeAll(removedGraphUris); - Set addedGraphUris = new HashSet(newGraphUris); - addedGraphUris.removeAll(oldGraphUris); - graphURIs.addAll(addedGraphUris); - } catch (Exception e) { - log.error(e, e); - } finally { - isRebuildGraphURICacheRunning = false; - rebuildGraphURICache = false; - } - } - } - } - }, "Rebuild graphURI cache thread"); - thread.start(); + Thread thread = new VitroBackgroundThread(new Runnable() { + public void run() { + synchronized (RDFServiceJena.class) { + if (rebuildGraphURICache) { + try { + isRebuildGraphURICacheRunning = true; + Set newGraphUris = new HashSet<>(); + try { + String fastJenaQuery = "SELECT DISTINCT ?g WHERE { GRAPH ?g {} } ORDER BY ?g"; + newGraphUris.addAll(getGraphURIsFromSparqlQuery(fastJenaQuery)); + } catch (Exception e) { + log.debug("Unable to use non-standard ARQ query for graph list", e); + } + if (graphURIs.isEmpty()) { + String standardQuery = "SELECT DISTINCT ?g WHERE { GRAPH ?g { ?s ?p ?o } }"; + newGraphUris.addAll(getGraphURIsFromSparqlQuery(standardQuery)); + } + Set oldGraphUris = new HashSet(graphURIs); + if (newGraphUris.equals(oldGraphUris)) { + return; + } + Set removedGraphUris = new HashSet(oldGraphUris); + removedGraphUris.removeAll(newGraphUris); + graphURIs.removeAll(removedGraphUris); + Set addedGraphUris = new HashSet(newGraphUris); + addedGraphUris.removeAll(oldGraphUris); + graphURIs.addAll(addedGraphUris); + } catch (Exception e) { + log.error(e, e); + } finally { + isRebuildGraphURICacheRunning = false; + rebuildGraphURICache = false; + } + } + } + } + }, "Rebuild graphURI cache thread"); + thread.start(); } private List getGraphURIsFromSparqlQuery(String queryString) throws RDFServiceException { From e314dca8181ff6e28836cd1dff6851c4a8e37629 Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Fri, 3 Nov 2023 10:12:28 +0100 Subject: [PATCH 4/6] refact: extracted method to update graph URIs in RDFServiceImpl --- .../webapp/rdfservice/impl/RDFServiceImpl.java | 15 +++++++++++++++ .../rdfservice/impl/jena/RDFServiceJena.java | 15 +++------------ .../impl/sparql/RDFServiceSparql.java | 17 ++++------------- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java index 0a9a48dda8..2abec46841 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java @@ -5,8 +5,10 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.Arrays; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; @@ -482,4 +484,17 @@ public VitroRequest getVitroRequest() { return vitroRequest; } + protected void updateGraphURIs(Set newURIs) { + Set oldURIs = new HashSet(graphURIs); + if (newURIs.equals(oldURIs)) { + return; + } + Set removedURIs = new HashSet(oldURIs); + removedURIs.removeAll(newURIs); + graphURIs.removeAll(removedURIs); + Set addedURIs = new HashSet(newURIs); + addedURIs.removeAll(oldURIs); + graphURIs.addAll(addedURIs); + } + } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java index 32658a8ead..1e7c464cec 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java @@ -315,26 +315,17 @@ public void run() { try { isRebuildGraphURICacheRunning = true; Dataset d = dw.getDataset(); - Set newGraphUris = new HashSet<>(); + Set newURIs = new HashSet<>(); d.begin(ReadWrite.READ); try { Iterator nameIt = d.listNames(); while (nameIt.hasNext()) { - newGraphUris.add(nameIt.next()); + newURIs.add(nameIt.next()); } } finally { d.end(); } - Set oldGraphUris = new HashSet(graphURIs); - if (newGraphUris.equals(oldGraphUris)) { - return; - } - Set removedGraphUris = new HashSet(oldGraphUris); - removedGraphUris.removeAll(newGraphUris); - graphURIs.removeAll(removedGraphUris); - Set addedGraphUris = new HashSet(newGraphUris); - addedGraphUris.removeAll(oldGraphUris); - graphURIs.addAll(addedGraphUris); + updateGraphURIs(newURIs); } catch (Exception e) { log.error(e, e); } finally { diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java index 525ea669e7..be9320065c 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java @@ -390,27 +390,18 @@ public void run() { if (rebuildGraphURICache) { try { isRebuildGraphURICacheRunning = true; - Set newGraphUris = new HashSet<>(); + Set newURIs = new HashSet<>(); try { String fastJenaQuery = "SELECT DISTINCT ?g WHERE { GRAPH ?g {} } ORDER BY ?g"; - newGraphUris.addAll(getGraphURIsFromSparqlQuery(fastJenaQuery)); + newURIs.addAll(getGraphURIsFromSparqlQuery(fastJenaQuery)); } catch (Exception e) { log.debug("Unable to use non-standard ARQ query for graph list", e); } if (graphURIs.isEmpty()) { String standardQuery = "SELECT DISTINCT ?g WHERE { GRAPH ?g { ?s ?p ?o } }"; - newGraphUris.addAll(getGraphURIsFromSparqlQuery(standardQuery)); + newURIs.addAll(getGraphURIsFromSparqlQuery(standardQuery)); } - Set oldGraphUris = new HashSet(graphURIs); - if (newGraphUris.equals(oldGraphUris)) { - return; - } - Set removedGraphUris = new HashSet(oldGraphUris); - removedGraphUris.removeAll(newGraphUris); - graphURIs.removeAll(removedGraphUris); - Set addedGraphUris = new HashSet(newGraphUris); - addedGraphUris.removeAll(oldGraphUris); - graphURIs.addAll(addedGraphUris); + updateGraphURIs(newURIs); } catch (Exception e) { log.error(e, e); } finally { From ec84b9955de71f8fd4bf96e6097c1149c4040944 Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Fri, 3 Nov 2023 11:25:41 +0100 Subject: [PATCH 5/6] style: fixed layout, removed files from checkstyle suppressions --- .../SameAsFilteringRDFServiceFactory.java | 139 +- .../rdfservice/impl/RDFServiceImpl.java | 360 ++-- .../rdfservice/impl/jena/RDFServiceJena.java | 364 ++-- .../impl/sparql/RDFServiceSparql.java | 1699 ++++++++--------- checkstyle-suppressions.xml | 6 +- 5 files changed, 1271 insertions(+), 1297 deletions(-) diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/SameAsFilteringRDFServiceFactory.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/SameAsFilteringRDFServiceFactory.java index 82f575f601..3d9dff381e 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/SameAsFilteringRDFServiceFactory.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/filter/SameAsFilteringRDFServiceFactory.java @@ -10,9 +10,17 @@ import java.util.Iterator; import java.util.List; +import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener; +import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService.ModelSerializationFormat; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; +import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceFactory; +import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer; +import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceImpl; +import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.apache.jena.query.Query; import org.apache.jena.query.QueryExecution; import org.apache.jena.query.QueryExecutionFactory; @@ -30,27 +38,18 @@ import org.apache.jena.rdf.model.StmtIterator; import org.apache.jena.vocabulary.OWL; -import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeListener; -import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet; -import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService; -import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService.ModelSerializationFormat; -import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException; -import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceFactory; -import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer; -import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceImpl; -import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils; - public class SameAsFilteringRDFServiceFactory implements RDFServiceFactory { - private final static Log log = LogFactory.getLog( - SameAsFilteringRDFServiceFactory.class); + private final static Log log = LogFactory.getLog(SameAsFilteringRDFServiceFactory.class); private RDFServiceFactory f; private Model sameAsModel; public SameAsFilteringRDFServiceFactory(RDFServiceFactory rdfServiceFactory) { this.f = rdfServiceFactory; try { - InputStream in = f.getRDFService().sparqlConstructQuery("CONSTRUCT { ?s <" + OWL.sameAs.getURI() + "> ?o } WHERE { ?s <" + OWL.sameAs.getURI() + "> ?o } ", ModelSerializationFormat.N3); + InputStream in = f.getRDFService().sparqlConstructQuery( + "CONSTRUCT { ?s <" + OWL.sameAs.getURI() + "> ?o } WHERE { ?s <" + OWL.sameAs.getURI() + "> ?o } ", + ModelSerializationFormat.N3); sameAsModel = RDFServiceUtils.parseModel(in, ModelSerializationFormat.N3); } catch (RDFServiceException e) { throw new RuntimeException(e); @@ -98,11 +97,9 @@ public SameAsFilteringRDFService(RDFService rdfService) { } @Override - public InputStream sparqlConstructQuery(String query, - RDFService.ModelSerializationFormat resultFormat) - throws RDFServiceException { - Model m = RDFServiceUtils.parseModel( - s.sparqlConstructQuery(query, resultFormat), resultFormat); + public InputStream sparqlConstructQuery(String query, RDFService.ModelSerializationFormat resultFormat) + throws RDFServiceException { + Model m = RDFServiceUtils.parseModel(s.sparqlConstructQuery(query, resultFormat), resultFormat); Model filtered = ModelFactory.createDefaultModel(); StmtIterator stmtIt = m.listStatements(); while (stmtIt.hasNext()) { @@ -112,14 +109,12 @@ public InputStream sparqlConstructQuery(String query, } } ByteArrayOutputStream out = new ByteArrayOutputStream(); - filtered.write(out, RDFServiceUtils.getSerializationFormatString( - resultFormat)); + filtered.write(out, RDFServiceUtils.getSerializationFormatString(resultFormat)); return new ByteArrayInputStream(out.toByteArray()); } @Override - public void sparqlConstructQuery(String query, Model model) - throws RDFServiceException { + public void sparqlConstructQuery(String query, Model model) throws RDFServiceException { Model m = ModelFactory.createDefaultModel(); s.sparqlConstructQuery(query, m); @@ -133,11 +128,9 @@ public void sparqlConstructQuery(String query, Model model) } @Override - public InputStream sparqlSelectQuery(String query, ResultFormat resultFormat) - throws RDFServiceException { - ResultSet rs = ResultSetFactory.load( - s.sparqlSelectQuery(query, resultFormat), - RDFServiceUtils.getJenaResultSetFormat(resultFormat)); + public InputStream sparqlSelectQuery(String query, ResultFormat resultFormat) throws RDFServiceException { + ResultSet rs = ResultSetFactory.load(s.sparqlSelectQuery(query, resultFormat), + RDFServiceUtils.getJenaResultSetFormat(resultFormat)); List solutions = new ArrayList(); while (rs.hasNext()) { QuerySolution solution = rs.nextSolution(); @@ -148,27 +141,26 @@ public InputStream sparqlSelectQuery(String query, ResultFormat resultFormat) ResultSet resultSet = new FilteredResultSet(solutions, rs); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); switch (resultFormat) { - case CSV: - ResultSetFormatter.outputAsCSV(outputStream,resultSet); - break; - case TEXT: - ResultSetFormatter.out(outputStream,resultSet); - break; - case JSON: - ResultSetFormatter.outputAsJSON(outputStream, resultSet); - break; - case XML: - ResultSetFormatter.outputAsXML(outputStream, resultSet); - break; - default: - throw new RDFServiceException("unrecognized result format"); + case CSV: + ResultSetFormatter.outputAsCSV(outputStream, resultSet); + break; + case TEXT: + ResultSetFormatter.out(outputStream, resultSet); + break; + case JSON: + ResultSetFormatter.outputAsJSON(outputStream, resultSet); + break; + case XML: + ResultSetFormatter.outputAsXML(outputStream, resultSet); + break; + default: + throw new RDFServiceException("unrecognized result format"); } return new ByteArrayInputStream(outputStream.toByteArray()); } @Override - public void sparqlSelectQuery(String query, ResultSetConsumer consumer) - throws RDFServiceException { + public void sparqlSelectQuery(String query, ResultSetConsumer consumer) throws RDFServiceException { s.sparqlSelectQuery(query, new ResultSetConsumer.Chaining(consumer) { @Override @@ -200,13 +192,14 @@ private List getSameAsResources(Resource resource) { if (resource.isAnon()) { return sameAsResources; } - String queryStr = "SELECT DISTINCT ?s WHERE { <" + resource.getURI() + "> <" + OWL.sameAs.getURI() + "> ?s } ORDER BY ?s"; - try { + String queryStr = "SELECT DISTINCT ?s WHERE { <" + resource.getURI() + "> <" + OWL.sameAs.getURI() + + "> ?s } ORDER BY ?s"; + try { Query query = QueryFactory.create(queryStr); QueryExecution qe = QueryExecutionFactory.create(query, sameAsModel); try { ResultSet rs = qe.execSelect(); - //ResultSet rs = JSONInput.fromJSON(s.sparqlSelectQuery(queryStr, ResultFormat.JSON)); + // ResultSet rs = JSONInput.fromJSON(s.sparqlSelectQuery(queryStr, ResultFormat.JSON)); while (rs.hasNext()) { QuerySolution q = rs.next(); Resource res = q.getResource("s"); @@ -219,14 +212,14 @@ private List getSameAsResources(Resource resource) { qe.close(); } return sameAsResources; - } catch (/*RDFService*/Exception e) { + } catch (/* RDFService */Exception e) { throw new RuntimeException(e); } } private boolean isRedundant(QuerySolution q) { Iterator varIt = q.varNames(); - while(varIt.hasNext()) { + while (varIt.hasNext()) { String varName = varIt.next(); RDFNode n = q.get(varName); if (n.isResource()) { @@ -241,17 +234,14 @@ private boolean isRedundant(QuerySolution q) { } @Override - public boolean changeSetUpdate(ChangeSet changeSet) - throws RDFServiceException { + public boolean changeSetUpdate(ChangeSet changeSet) throws RDFServiceException { return s.changeSetUpdate(changeSet); } @Override - public InputStream sparqlDescribeQuery(String query, - ModelSerializationFormat resultFormat) + public InputStream sparqlDescribeQuery(String query, ModelSerializationFormat resultFormat) throws RDFServiceException { - Model m = RDFServiceUtils.parseModel( - s.sparqlConstructQuery(query, resultFormat), resultFormat); + Model m = RDFServiceUtils.parseModel(s.sparqlConstructQuery(query, resultFormat), resultFormat); Model filtered = ModelFactory.createDefaultModel(); StmtIterator stmtIt = m.listStatements(); while (stmtIt.hasNext()) { @@ -261,8 +251,7 @@ public InputStream sparqlDescribeQuery(String query, } } ByteArrayOutputStream out = new ByteArrayOutputStream(); - filtered.write(out, RDFServiceUtils.getSerializationFormatString( - resultFormat)); + filtered.write(out, RDFServiceUtils.getSerializationFormatString(resultFormat)); return new ByteArrayInputStream(out.toByteArray()); } @@ -282,27 +271,23 @@ public void getGraphMetadata() throws RDFServiceException { } @Override - public void serializeAll(OutputStream outputStream) - throws RDFServiceException { - s.serializeAll(outputStream); - } - - @Override - public void serializeGraph(String graphURI, OutputStream outputStream) - throws RDFServiceException { - s.serializeGraph(graphURI, outputStream); - } - - @Override - public boolean isEquivalentGraph(String graphURI, - InputStream serializedGraph, - ModelSerializationFormat serializationFormat) throws RDFServiceException { - return s.isEquivalentGraph(graphURI, serializedGraph, serializationFormat); - } + public void serializeAll(OutputStream outputStream) throws RDFServiceException { + s.serializeAll(outputStream); + } @Override - public boolean isEquivalentGraph(String graphURI, - Model graph) throws RDFServiceException { + public void serializeGraph(String graphURI, OutputStream outputStream) throws RDFServiceException { + s.serializeGraph(graphURI, outputStream); + } + + @Override + public boolean isEquivalentGraph(String graphURI, InputStream serializedGraph, + ModelSerializationFormat serializationFormat) throws RDFServiceException { + return s.isEquivalentGraph(graphURI, serializedGraph, serializationFormat); + } + + @Override + public boolean isEquivalentGraph(String graphURI, Model graph) throws RDFServiceException { return s.isEquivalentGraph(graphURI, graph); } @@ -320,8 +305,6 @@ public void close() { protected void rebuildGraphUris() { } - } - } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java index 2abec46841..69e7c16f11 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/RDFServiceImpl.java @@ -44,113 +44,113 @@ public abstract class RDFServiceImpl implements RDFService { - private static final Log log = LogFactory.getLog(RDFServiceImpl.class); - - protected String defaultWriteGraphURI; - protected List registeredListeners = new CopyOnWriteArrayList(); - protected List registeredJenaListeners = new CopyOnWriteArrayList(); - protected final List graphURIs = new CopyOnWriteArrayList(); - protected volatile boolean rebuildGraphURICache = true; - protected volatile boolean isRebuildGraphURICacheRunning = false; - - @Override - public void newIndividual(String individualURI, - String individualTypeURI) throws RDFServiceException { - - newIndividual(individualURI, individualTypeURI, defaultWriteGraphURI); - } + private static final Log log = LogFactory.getLog(RDFServiceImpl.class); + + protected String defaultWriteGraphURI; + protected List registeredListeners = new CopyOnWriteArrayList(); + protected List registeredJenaListeners = new CopyOnWriteArrayList(); + protected final List graphURIs = new CopyOnWriteArrayList(); + protected volatile boolean rebuildGraphURICache = true; + protected volatile boolean isRebuildGraphURICacheRunning = false; + + @Override + public void newIndividual(String individualURI, String individualTypeURI) throws RDFServiceException { + + newIndividual(individualURI, individualTypeURI, defaultWriteGraphURI); + } @Override - public void newIndividual(String individualURI, - String individualTypeURI, - String graphURI) throws RDFServiceException { - - StringBuilder containsQuery = new StringBuilder("ASK { \n"); - if (graphURI != null) { - containsQuery.append(" GRAPH <").append(graphURI).append("> { "); - } - containsQuery.append("<"); - containsQuery.append(individualURI); - containsQuery.append("> "); - containsQuery.append("?p ?o"); - if (graphURI != null) { - containsQuery.append(" } \n"); - } - containsQuery.append("\n}"); - - if (sparqlAskQuery(containsQuery.toString())) { + public void newIndividual(String individualURI, String individualTypeURI, String graphURI) + throws RDFServiceException { + + StringBuilder containsQuery = new StringBuilder("ASK { \n"); + if (graphURI != null) { + containsQuery.append(" GRAPH <").append(graphURI).append("> { "); + } + containsQuery.append("<"); + containsQuery.append(individualURI); + containsQuery.append("> "); + containsQuery.append("?p ?o"); + if (graphURI != null) { + containsQuery.append(" } \n"); + } + containsQuery.append("\n}"); + + if (sparqlAskQuery(containsQuery.toString())) { throw new RDFServiceException("individual already exists"); - } else { - Triple triple = new Triple(NodeFactory.createURI(individualURI), RDF.type.asNode(), NodeFactory.createURI(individualTypeURI)); - //addTriple(triple, graphURI); + } else { + Triple triple = new Triple(NodeFactory.createURI(individualURI), RDF.type.asNode(), + NodeFactory.createURI(individualTypeURI)); + // addTriple(triple, graphURI); ChangeSet cs = this.manufactureChangeSet(); - cs.addAddition(new ByteArrayInputStream( - sparqlTriple(triple).getBytes()), ModelSerializationFormat.N3, graphURI); + cs.addAddition(new ByteArrayInputStream(sparqlTriple(triple).getBytes()), ModelSerializationFormat.N3, + graphURI); changeSetUpdate(cs); - } - } - - /** - * Get a list of all the graph URIs in the RDF store. - */ - @Override - public List getGraphURIs() throws RDFServiceException { - if (rebuildGraphURICache && !isRebuildGraphURICacheRunning) { - rebuildGraphUris(); - } - return graphURIs; - } - - protected abstract void rebuildGraphUris(); - - @Override - public String getDefaultWriteGraphURI() throws RDFServiceException { - return defaultWriteGraphURI; - } - - @Override - public synchronized void registerListener(ChangeListener changeListener) throws RDFServiceException { - if (!registeredListeners.contains(changeListener)) { - registeredListeners.add(changeListener); - } - } - - @Override - public synchronized void unregisterListener(ChangeListener changeListener) throws RDFServiceException { - registeredListeners.remove(changeListener); - } - - @Override - public synchronized void registerJenaModelChangedListener(ModelChangedListener changeListener) throws RDFServiceException { - if (!registeredJenaListeners.contains(changeListener)) { - registeredJenaListeners.add(changeListener); - } - } - - @Override - public synchronized void unregisterJenaModelChangedListener(ModelChangedListener changeListener) throws RDFServiceException { - registeredJenaListeners.remove(changeListener); - } - - public synchronized List getRegisteredListeners() { - return this.registeredListeners; - } - - public synchronized List getRegisteredJenaModelChangedListeners() { - return this.registeredJenaListeners; - } - - @Override - public ChangeSet manufactureChangeSet() { - return new ChangeSetImpl(); - } - - protected void notifyListenersOfChanges(ChangeSet changeSet) - throws IOException { + } + } + + /** + * Get a list of all the graph URIs in the RDF store. + */ + @Override + public List getGraphURIs() throws RDFServiceException { + if (rebuildGraphURICache && !isRebuildGraphURICacheRunning) { + rebuildGraphUris(); + } + return graphURIs; + } + + protected abstract void rebuildGraphUris(); + + @Override + public String getDefaultWriteGraphURI() throws RDFServiceException { + return defaultWriteGraphURI; + } + + @Override + public synchronized void registerListener(ChangeListener changeListener) throws RDFServiceException { + if (!registeredListeners.contains(changeListener)) { + registeredListeners.add(changeListener); + } + } + + @Override + public synchronized void unregisterListener(ChangeListener changeListener) throws RDFServiceException { + registeredListeners.remove(changeListener); + } + + @Override + public synchronized void registerJenaModelChangedListener(ModelChangedListener changeListener) + throws RDFServiceException { + if (!registeredJenaListeners.contains(changeListener)) { + registeredJenaListeners.add(changeListener); + } + } + + @Override + public synchronized void unregisterJenaModelChangedListener(ModelChangedListener changeListener) + throws RDFServiceException { + registeredJenaListeners.remove(changeListener); + } + + public synchronized List getRegisteredListeners() { + return this.registeredListeners; + } + + public synchronized List getRegisteredJenaModelChangedListeners() { + return this.registeredJenaListeners; + } + + @Override + public ChangeSet manufactureChangeSet() { + return new ChangeSetImpl(); + } + + protected void notifyListenersOfChanges(ChangeSet changeSet) throws IOException { if (registeredListeners.isEmpty() && registeredJenaListeners.isEmpty()) { return; } - for (ModelChange modelChange: changeSet.getModelChanges()) { + for (ModelChange modelChange : changeSet.getModelChanges()) { notifyListeners(modelChange); } } @@ -174,12 +174,10 @@ protected void notifyListeners(ModelChange modelChange) throws IOException { } if (Operation.ADD.equals(modelChange.getOperation())) { tempModel.read(modelChange.getSerializedModel(), null, - RDFServiceUtils.getSerializationFormatString( - modelChange.getSerializationFormat())); + RDFServiceUtils.getSerializationFormatString(modelChange.getSerializationFormat())); } else if (Operation.REMOVE.equals(modelChange.getOperation())) { - tempModel.remove(RDFServiceUtils.parseModel( - modelChange.getSerializedModel(), - modelChange.getSerializationFormat())); + tempModel.remove( + RDFServiceUtils.parseModel(modelChange.getSerializedModel(), modelChange.getSerializationFormat())); } while (jenaIter.hasNext()) { tempModel.unregister(jenaIter.next()); @@ -196,16 +194,15 @@ public void notifyListenersOfEvent(Object event) { } } - protected boolean isPreconditionSatisfied(String query, - RDFService.SPARQLQueryType queryType) - throws RDFServiceException { + protected boolean isPreconditionSatisfied(String query, RDFService.SPARQLQueryType queryType) + throws RDFServiceException { Model model = ModelFactory.createDefaultModel(); switch (queryType) { case DESCRIBE: - model.read(sparqlDescribeQuery(query,RDFService.ModelSerializationFormat.N3), null); + model.read(sparqlDescribeQuery(query, RDFService.ModelSerializationFormat.N3), null); return !model.isEmpty(); case CONSTRUCT: - model.read(sparqlConstructQuery(query,RDFService.ModelSerializationFormat.N3), null); + model.read(sparqlConstructQuery(query, RDFService.ModelSerializationFormat.N3), null); return !model.isEmpty(); case SELECT: return sparqlSelectQueryHasResults(query); @@ -281,36 +278,54 @@ protected static String sparqlNode(Node node, String varName) { } } - // see http://www.python.org/doc/2.5.2/ref/strings.html - // or see jena's n3 grammar jena/src/org.apache/jena/n3/n3.g - protected static void pyString(StringBuffer sbuff, String s) { + // see http://www.python.org/doc/2.5.2/ref/strings.html + // or see jena's n3 grammar jena/src/org.apache/jena/n3/n3.g + protected static void pyString(StringBuffer sbuff, String s) { for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); // Escape escapes and quotes - if (c == '\\' || c == '"' ) - { - sbuff.append('\\') ; - sbuff.append(c) ; - continue ; + if (c == '\\' || c == '"') { + sbuff.append('\\'); + sbuff.append(c); + continue; } // Whitespace - if (c == '\n'){ sbuff.append("\\n");continue; } - if (c == '\t'){ sbuff.append("\\t");continue; } - if (c == '\r'){ sbuff.append("\\r");continue; } - if (c == '\f'){ sbuff.append("\\f");continue; } - if (c == '\b'){ sbuff.append("\\b");continue; } - if( c == 7 ) { sbuff.append("\\a");continue; } + if (c == '\n') { + sbuff.append("\\n"); + continue; + } + if (c == '\t') { + sbuff.append("\\t"); + continue; + } + if (c == '\r') { + sbuff.append("\\r"); + continue; + } + if (c == '\f') { + sbuff.append("\\f"); + continue; + } + if (c == '\b') { + sbuff.append("\\b"); + continue; + } + if (c == 7) { + sbuff.append("\\a"); + continue; + } // Output as is (subject to UTF-8 encoding on output that is) - sbuff.append(c) ; + sbuff.append(c); } } /** - * Returns a pair of models. The first contains any statement containing at - * least one blank node. The second contains all remaining statements. + * Returns a pair of models. The first contains any statement containing at least one blank node. The second + * contains all remaining statements. + * * @param gm Jena model */ @@ -333,47 +348,45 @@ protected Model[] separateStatementsWithBlankNodes(Model gm) { } protected Query createQuery(String queryString) throws RDFServiceException { - List syntaxes = Arrays.asList( - Syntax.defaultQuerySyntax, Syntax.syntaxSPARQL_11, - Syntax.syntaxSPARQL_10, Syntax.syntaxSPARQL, Syntax.syntaxARQ); + List syntaxes = Arrays.asList(Syntax.defaultQuerySyntax, Syntax.syntaxSPARQL_11, Syntax.syntaxSPARQL_10, + Syntax.syntaxSPARQL, Syntax.syntaxARQ); Query q = null; Iterator syntaxIt = syntaxes.iterator(); while (q == null) { Syntax syntax = syntaxIt.next(); try { - q = QueryFactory.create(queryString, syntax); + q = QueryFactory.create(queryString, syntax); } catch (QueryParseException e) { - if (!syntaxIt.hasNext()) { - throw new RDFServiceException("Failed to parse query \"" - + queryString + "\"", e); - } + if (!syntaxIt.hasNext()) { + throw new RDFServiceException("Failed to parse query \"" + queryString + "\"", e); + } } } return q; } - @Override - public String toString() { - return ToString.simpleName(this) + "[" + ToString.hashHex(this) + "]"; - } + @Override + public String toString() { + return ToString.simpleName(this) + "[" + ToString.hashHex(this) + "]"; + } @Override public long countTriples(RDFNode subject, RDFNode predicate, RDFNode object) throws RDFServiceException { StringBuilder whereClause = new StringBuilder(); - if ( subject != null ) { + if (subject != null) { appendNode(whereClause.append(' '), subject); } else { whereClause.append(" ?s"); } - if ( predicate != null ) { + if (predicate != null) { appendNode(whereClause.append(' '), predicate); } else { whereClause.append(" ?p"); } - if ( object != null ) { + if (object != null) { appendNode(whereClause.append(' '), object); } else { whereClause.append(" ?o"); @@ -392,25 +405,26 @@ public long countTriples(RDFNode subject, RDFNode predicate, RDFNode object) thr } @Override - public Model getTriples(RDFNode subject, RDFNode predicate, RDFNode object, long limit, long offset) throws RDFServiceException { + public Model getTriples(RDFNode subject, RDFNode predicate, RDFNode object, long limit, long offset) + throws RDFServiceException { StringBuilder whereClause = new StringBuilder(); StringBuilder orderBy = new StringBuilder(); - if ( subject != null ) { + if (subject != null) { appendNode(whereClause.append(' '), subject); } else { whereClause.append(" ?s"); orderBy.append(" ?s"); } - if ( predicate != null ) { + if (predicate != null) { appendNode(whereClause.append(' '), predicate); } else { whereClause.append(" ?p"); orderBy.append(" ?p"); } - if ( object != null ) { + if (object != null) { appendNode(whereClause.append(' '), object); } else { whereClause.append(" ?o"); @@ -469,32 +483,34 @@ protected void processQuerySolution(QuerySolution qs) { } } } - /* - * UQAM Useful among other things to transport the linguistic context in the service - * (non-Javadoc) - * @see edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService#setVitroRequest(edu.cornell.mannlib.vitro.webapp.controller.VitroRequest) - */ - private VitroRequest vitroRequest; - - public void setVitroRequest(VitroRequest vitroRequest) { - this.vitroRequest = vitroRequest; - } - - public VitroRequest getVitroRequest() { - return vitroRequest; - } - - protected void updateGraphURIs(Set newURIs) { - Set oldURIs = new HashSet(graphURIs); - if (newURIs.equals(oldURIs)) { - return; - } - Set removedURIs = new HashSet(oldURIs); - removedURIs.removeAll(newURIs); - graphURIs.removeAll(removedURIs); - Set addedURIs = new HashSet(newURIs); - addedURIs.removeAll(oldURIs); - graphURIs.addAll(addedURIs); - } + + /* + * UQAM Useful among other things to transport the linguistic context in the service (non-Javadoc) + * + * @see edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService#setVitroRequest(edu.cornell.mannlib.vitro.webapp. + * controller.VitroRequest) + */ + private VitroRequest vitroRequest; + + public void setVitroRequest(VitroRequest vitroRequest) { + this.vitroRequest = vitroRequest; + } + + public VitroRequest getVitroRequest() { + return vitroRequest; + } + + protected void updateGraphURIs(Set newURIs) { + Set oldURIs = new HashSet(graphURIs); + if (newURIs.equals(oldURIs)) { + return; + } + Set removedURIs = new HashSet(oldURIs); + removedURIs.removeAll(newURIs); + graphURIs.removeAll(removedURIs); + Set addedURIs = new HashSet(newURIs); + addedURIs.removeAll(oldURIs); + graphURIs.addAll(addedURIs); + } } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java index 1e7c464cec..eba2bda568 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java @@ -57,53 +57,52 @@ public abstract class RDFServiceJena extends RDFServiceImpl implements RDFServic protected abstract DatasetWrapper getDatasetWrapper(); @Override - public abstract boolean changeSetUpdate(ChangeSet changeSet) throws RDFServiceException; + public abstract boolean changeSetUpdate(ChangeSet changeSet) throws RDFServiceException; protected void notifyListenersOfPreChangeEvents(ChangeSet changeSet) { - for (Object o : changeSet.getPreChangeEvents()) { - this.notifyListenersOfEvent(o); - } - } + for (Object o : changeSet.getPreChangeEvents()) { + this.notifyListenersOfEvent(o); + } + } protected void insureThatInputStreamsAreResettable(ChangeSet changeSet) throws IOException { - for (ModelChange modelChange: changeSet.getModelChanges()) { + for (ModelChange modelChange : changeSet.getModelChanges()) { if (!modelChange.getSerializedModel().markSupported()) { byte[] bytes = IOUtils.toByteArray(modelChange.getSerializedModel()); modelChange.setSerializedModel(new ByteArrayInputStream(bytes)); } modelChange.getSerializedModel().mark(Integer.MAX_VALUE); } - } + } protected void applyChangeSetToModel(ChangeSet changeSet, Dataset dataset) { - for (ModelChange modelChange: changeSet.getModelChanges()) { - dataset.getLock().enterCriticalSection(Lock.WRITE); - try { - Model model = (modelChange.getGraphURI() == null) ? - dataset.getDefaultModel() : - dataset.getNamedModel(modelChange.getGraphURI()); - operateOnModel(model, modelChange); - } finally { - dataset.getLock().leaveCriticalSection(); - } - } - } + for (ModelChange modelChange : changeSet.getModelChanges()) { + dataset.getLock().enterCriticalSection(Lock.WRITE); + try { + Model model = (modelChange.getGraphURI() == null) ? dataset.getDefaultModel() + : dataset.getNamedModel(modelChange.getGraphURI()); + operateOnModel(model, modelChange); + } finally { + dataset.getLock().leaveCriticalSection(); + } + } + } protected void notifyListenersOfPostChangeEvents(ChangeSet changeSet) { - for (Object o : changeSet.getPostChangeEvents()) { - this.notifyListenersOfEvent(o); - } - } + for (Object o : changeSet.getPostChangeEvents()) { + this.notifyListenersOfEvent(o); + } + } protected void operateOnModel(Model model, ModelChange modelChange) { model.enterCriticalSection(Lock.WRITE); try { - if (log.isDebugEnabled()) { - dumpOperation(model, modelChange); - } + if (log.isDebugEnabled()) { + dumpOperation(model, modelChange); + } if (modelChange.getOperation() == ModelChange.Operation.ADD) { - Model addition = parseModel(modelChange); - model.add(addition); + Model addition = parseModel(modelChange); + model.add(addition); } else if (modelChange.getOperation() == ModelChange.Operation.REMOVE) { Model removal = parseModel(modelChange); JenaModelUtils.removeWithBlankNodesAsVariables(removal, model); @@ -115,56 +114,52 @@ protected void operateOnModel(Model model, ModelChange modelChange) { } } - /** - * As a debug statement, log info about the model change operation: add or - * delete, model URI, model class, punctuation count, beginning of the - * string. - */ - private void dumpOperation(Model model, ModelChange modelChange) { - String op = String.valueOf(modelChange.getOperation()); - - byte[] changeBytes = new byte[0]; - try { - modelChange.getSerializedModel().mark(Integer.MAX_VALUE); - changeBytes = IOUtils.toByteArray(modelChange.getSerializedModel()); - modelChange.getSerializedModel().reset(); - } catch (IOException e) { - // leave it empty. - } - - int puncCount = 0; - boolean inUri = false; - boolean inQuotes = false; - for (byte b : changeBytes) { - if (inQuotes) { - if (b == '"') { - inQuotes = false; - } - } else if (inUri) { - if (b == '>') { - inUri = false; - } - } else { - if (b == '"') { - inQuotes = true; - } else if (b == '<') { - inUri = true; - } else if ((b == ',') || (b == ';') || (b == '.')) { - puncCount++; - } - } - } - - String changeString = new String(changeBytes).replace('\n', ' '); - - log.debug(String.format( - ">>>>OPERATION: %3.3s %03dpunc, format=%s, graphUri='%s'\n" - + " start=%.200s\n" + " model=%s", - modelChange.getOperation(), puncCount, - modelChange.getSerializationFormat(), - modelChange.getGraphURI(), changeString, - ToString.modelToString(model))); - } + /** + * As a debug statement, log info about the model change operation: add or delete, model URI, model class, + * punctuation count, beginning of the string. + */ + private void dumpOperation(Model model, ModelChange modelChange) { + String op = String.valueOf(modelChange.getOperation()); + + byte[] changeBytes = new byte[0]; + try { + modelChange.getSerializedModel().mark(Integer.MAX_VALUE); + changeBytes = IOUtils.toByteArray(modelChange.getSerializedModel()); + modelChange.getSerializedModel().reset(); + } catch (IOException e) { + // leave it empty. + } + + int puncCount = 0; + boolean inUri = false; + boolean inQuotes = false; + for (byte b : changeBytes) { + if (inQuotes) { + if (b == '"') { + inQuotes = false; + } + } else if (inUri) { + if (b == '>') { + inUri = false; + } + } else { + if (b == '"') { + inQuotes = true; + } else if (b == '<') { + inUri = true; + } else if ((b == ',') || (b == ';') || (b == '.')) { + puncCount++; + } + } + } + + String changeString = new String(changeBytes).replace('\n', ' '); + + log.debug(String.format( + ">>>>OPERATION: %3.3s %03dpunc, format=%s, graphUri='%s'\n" + " start=%.200s\n" + " model=%s", + modelChange.getOperation(), puncCount, modelChange.getSerializationFormat(), modelChange.getGraphURI(), + changeString, ToString.modelToString(model))); + } private Model parseModel(ModelChange modelChange) { Model model = ModelFactory.createDefaultModel(); @@ -173,8 +168,8 @@ private Model parseModel(ModelChange modelChange) { return model; } - private InputStream getRDFResultStream(String query, boolean construct, - ModelSerializationFormat resultFormat) throws RDFServiceException { + private InputStream getRDFResultStream(String query, boolean construct, ModelSerializationFormat resultFormat) + throws RDFServiceException { DatasetWrapper dw = getDatasetWrapper(); try { Dataset d = dw.getDataset(); @@ -216,8 +211,8 @@ private void getRDFModel(String query, boolean construct, Model model) throws RD private static final boolean DESCRIBE = false; @Override - public InputStream sparqlConstructQuery(String query, - ModelSerializationFormat resultFormat) throws RDFServiceException { + public InputStream sparqlConstructQuery(String query, ModelSerializationFormat resultFormat) + throws RDFServiceException { return getRDFResultStream(query, CONSTRUCT, resultFormat); } @@ -226,17 +221,16 @@ public void sparqlConstructQuery(String query, Model model) throws RDFServiceExc } @Override - public InputStream sparqlDescribeQuery(String query, - ModelSerializationFormat resultFormat) throws RDFServiceException { + public InputStream sparqlDescribeQuery(String query, ModelSerializationFormat resultFormat) + throws RDFServiceException { return getRDFResultStream(query, DESCRIBE, resultFormat); } - /** - * TODO Is there a way to accomplish this without buffering the entire result? - */ + /** + * TODO Is there a way to accomplish this without buffering the entire result? + */ @Override - public InputStream sparqlSelectQuery(String query, ResultFormat resultFormat) - throws RDFServiceException { + public InputStream sparqlSelectQuery(String query, ResultFormat resultFormat) throws RDFServiceException { DatasetWrapper dw = getDatasetWrapper(); try { Dataset d = dw.getDataset(); @@ -246,20 +240,20 @@ public InputStream sparqlSelectQuery(String query, ResultFormat resultFormat) ResultSet resultSet = qe.execSelect(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); switch (resultFormat) { - case CSV: - ResultSetFormatter.outputAsCSV(outputStream,resultSet); - break; - case TEXT: - ResultSetFormatter.out(outputStream,resultSet); - break; - case JSON: - ResultSetFormatter.outputAsJSON(outputStream, resultSet); - break; - case XML: - ResultSetFormatter.outputAsXML(outputStream, resultSet); - break; - default: - throw new RDFServiceException("unrecognized result format"); + case CSV: + ResultSetFormatter.outputAsCSV(outputStream, resultSet); + break; + case TEXT: + ResultSetFormatter.out(outputStream, resultSet); + break; + case JSON: + ResultSetFormatter.outputAsJSON(outputStream, resultSet); + break; + case XML: + ResultSetFormatter.outputAsXML(outputStream, resultSet); + break; + default: + throw new RDFServiceException("unrecognized result format"); } InputStream result = new ByteArrayInputStream(outputStream.toByteArray()); return result; @@ -272,8 +266,7 @@ public InputStream sparqlSelectQuery(String query, ResultFormat resultFormat) } @Override - public void sparqlSelectQuery(String query, ResultSetConsumer consumer) - throws RDFServiceException { + public void sparqlSelectQuery(String query, ResultSetConsumer consumer) throws RDFServiceException { DatasetWrapper dw = getDatasetWrapper(); try { Dataset d = dw.getDataset(); @@ -289,7 +282,7 @@ public void sparqlSelectQuery(String query, ResultSetConsumer consumer) } } - @Override + @Override public boolean sparqlAskQuery(String query) throws RDFServiceException { DatasetWrapper dw = getDatasetWrapper(); try { @@ -342,66 +335,64 @@ public void run() { @Override public void getGraphMetadata() throws RDFServiceException { - // nothing to do + // nothing to do } @Override - public void serializeAll(OutputStream outputStream) - throws RDFServiceException { - String query = "SELECT * WHERE { GRAPH ?g {?s ?p ?o}}"; - serialize(outputStream, query); - } - - @Override - public void serializeGraph(String graphURI, OutputStream outputStream) - throws RDFServiceException { - String query = "SELECT * WHERE { GRAPH <" + graphURI + "> {?s ?p ?o}}"; - serialize(outputStream, query); - } - - private void serialize(OutputStream outputStream, String query) throws RDFServiceException { - DatasetWrapper dw = getDatasetWrapper(); - try { - Dataset d = dw.getDataset(); - Query q = createQuery(query); - QueryExecution qe = createQueryExecution(query, q, d); - // These properties only help for SDB, but shouldn't hurt for TDB. - qe.getContext().set(SDB.jdbcFetchSize, Integer.MIN_VALUE); - qe.getContext().set(SDB.jdbcStream, true); - qe.getContext().set(SDB.streamGraphAPI, true); - try { - ResultSet resultSet = qe.execSelect(); - if (resultSet.getResultVars().contains("g")) { - Iterator quads = new ResultSetQuadsIterator(resultSet); - RDFDataMgr.writeQuads(outputStream, quads); - } else { - Iterator triples = new ResultSetTriplesIterator(resultSet); - RDFDataMgr.writeTriples(outputStream, triples); - } - } finally { - qe.close(); - } - } finally { - dw.close(); - } - } - - /** - * The basic version. Parse the model from the file, read the model from the - * tripleStore, and ask whether they are isomorphic. - */ - @Override - public boolean isEquivalentGraph(String graphURI, InputStream serializedGraph, - ModelSerializationFormat serializationFormat) throws RDFServiceException { - Model fileModel = RDFServiceUtils.parseModel(serializedGraph, serializationFormat); - Model tripleStoreModel = new RDFServiceDataset(this).getNamedModel(graphURI); - Model fromTripleStoreModel = ModelFactory.createDefaultModel().add(tripleStoreModel); - return fileModel.isIsomorphicWith(fromTripleStoreModel); - } + public void serializeAll(OutputStream outputStream) throws RDFServiceException { + String query = "SELECT * WHERE { GRAPH ?g {?s ?p ?o}}"; + serialize(outputStream, query); + } + + @Override + public void serializeGraph(String graphURI, OutputStream outputStream) throws RDFServiceException { + String query = "SELECT * WHERE { GRAPH <" + graphURI + "> {?s ?p ?o}}"; + serialize(outputStream, query); + } + + private void serialize(OutputStream outputStream, String query) throws RDFServiceException { + DatasetWrapper dw = getDatasetWrapper(); + try { + Dataset d = dw.getDataset(); + Query q = createQuery(query); + QueryExecution qe = createQueryExecution(query, q, d); + // These properties only help for SDB, but shouldn't hurt for TDB. + qe.getContext().set(SDB.jdbcFetchSize, Integer.MIN_VALUE); + qe.getContext().set(SDB.jdbcStream, true); + qe.getContext().set(SDB.streamGraphAPI, true); + try { + ResultSet resultSet = qe.execSelect(); + if (resultSet.getResultVars().contains("g")) { + Iterator quads = new ResultSetQuadsIterator(resultSet); + RDFDataMgr.writeQuads(outputStream, quads); + } else { + Iterator triples = new ResultSetTriplesIterator(resultSet); + RDFDataMgr.writeTriples(outputStream, triples); + } + } finally { + qe.close(); + } + } finally { + dw.close(); + } + } /** - * The basic version. Parse the model from the file, read the model from the - * tripleStore, and ask whether they are isomorphic. + * The basic version. Parse the model from the file, read the model from the tripleStore, and ask whether they are + * isomorphic. + */ + @Override + public boolean isEquivalentGraph(String graphURI, InputStream serializedGraph, + ModelSerializationFormat serializationFormat) throws RDFServiceException { + Model fileModel = RDFServiceUtils.parseModel(serializedGraph, serializationFormat); + Model tripleStoreModel = new RDFServiceDataset(this).getNamedModel(graphURI); + Model fromTripleStoreModel = ModelFactory.createDefaultModel().add(tripleStoreModel); + return fileModel.isIsomorphicWith(fromTripleStoreModel); + } + + /** + * The basic version. Parse the model from the file, read the model from the tripleStore, and ask whether they are + * isomorphic. */ @Override public boolean isEquivalentGraph(String graphURI, Model graph) throws RDFServiceException { @@ -416,15 +407,16 @@ public boolean isEquivalentGraph(String graphURI, Model graph) throws RDFService @Override public long countTriples(RDFNode subject, RDFNode predicate, RDFNode object) throws RDFServiceException { - Query countQuery = QueryFactory.create("SELECT (COUNT(?s) AS ?count) WHERE { ?s ?p ?o } ORDER BY ?s ?p ?o", Syntax.syntaxSPARQL_11); + Query countQuery = QueryFactory.create("SELECT (COUNT(?s) AS ?count) WHERE { ?s ?p ?o } ORDER BY ?s ?p ?o", + Syntax.syntaxSPARQL_11); QuerySolutionMap map = new QuerySolutionMap(); - if ( subject != null ) { + if (subject != null) { map.add("s", subject); } - if ( predicate != null ) { + if (predicate != null) { map.add("p", predicate); } - if ( object != null ) { + if (object != null) { map.add("o", object); } @@ -434,7 +426,7 @@ public long countTriples(RDFNode subject, RDFNode predicate, RDFNode object) thr try (QueryExecution qexec = QueryExecutionFactory.create(countQuery, d, map)) { ResultSet results = qexec.execSelect(); if (results.hasNext()) { - QuerySolution soln = results.nextSolution() ; + QuerySolution soln = results.nextSolution(); Literal literal = soln.getLiteral("count"); return literal.getLong(); } @@ -447,16 +439,17 @@ public long countTriples(RDFNode subject, RDFNode predicate, RDFNode object) thr } @Override - public Model getTriples(RDFNode subject, RDFNode predicate, RDFNode object, long limit, long offset) throws RDFServiceException { + public Model getTriples(RDFNode subject, RDFNode predicate, RDFNode object, long limit, long offset) + throws RDFServiceException { Query query = QueryFactory.create("CONSTRUCT WHERE { ?s ?p ?o }", Syntax.syntaxSPARQL_11); QuerySolutionMap map = new QuerySolutionMap(); - if ( subject != null ) { + if (subject != null) { map.add("s", subject); } - if ( predicate != null ) { + if (predicate != null) { map.add("p", predicate); } - if ( object != null ) { + if (object != null) { map.add("o", object); } @@ -491,19 +484,22 @@ public void close() { protected QueryExecution createQueryExecution(String queryString, Query q, Dataset d) { return QueryExecutionFactory.create(q, d); } - /* - * UQAM-Linguistic-Management Useful among other things to transport the linguistic context in the service - * (non-Javadoc) - * @see edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService#setVitroRequest(edu.cornell.mannlib.vitro.webapp.controller.VitroRequest) - */ - private VitroRequest vitroRequest; - - public void setVitroRequest(VitroRequest vitroRequest) { - this.vitroRequest = vitroRequest; - } - - public VitroRequest getVitroRequest() { - return vitroRequest; - } + + /* + * UQAM-Linguistic-Management Useful among other things to transport the linguistic context in the service + * (non-Javadoc) + * + * @see edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService#setVitroRequest(edu.cornell.mannlib.vitro.webapp. + * controller.VitroRequest) + */ + private VitroRequest vitroRequest; + + public void setVitroRequest(VitroRequest vitroRequest) { + this.vitroRequest = vitroRequest; + } + + public VitroRequest getVitroRequest() { + return vitroRequest; + } } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java index be9320065c..5457c64e2e 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java @@ -81,865 +81,848 @@ */ public class RDFServiceSparql extends RDFServiceImpl implements RDFService { - private static final Log log = LogFactory.getLog(RDFServiceImpl.class); - protected String readEndpointURI; - protected String updateEndpointURI; - // the number of triples to be - private static final int CHUNK_SIZE = 5000; // added/removed in a single - // SPARQL UPDATE - - protected HttpClient httpClient; - - /** - * Returns an RDFService for a remote repository - * @param readEndpointURI - URI of the read SPARQL endpoint for the knowledge base - * @param updateEndpointURI - URI of the update SPARQL endpoint for the knowledge base - * @param defaultWriteGraphURI - URI of the default write graph within the knowledge base. - * this is the graph that will be written to when a graph - * is not explicitly specified. - * - * The default read graph is the union of all graphs in the - * knowledge base - */ - public RDFServiceSparql(String readEndpointURI, String updateEndpointURI, String defaultWriteGraphURI) { - this.readEndpointURI = readEndpointURI; - this.updateEndpointURI = updateEndpointURI; - httpClient = HttpClientFactory.getHttpClient(); - - if (RDFServiceSparql.class.getName().equals(this.getClass().getName())) { - testConnection(); - } - } - - protected void testConnection() { - try { - this.sparqlSelectQuery( - "SELECT ?s WHERE { ?s a " + - " }", - RDFService.ResultFormat.JSON); - } catch (Exception e) { - throw new RuntimeException("Unable to connect to endpoint at " + - readEndpointURI, e); - } - } - - /** - * Returns an RDFService for a remote repository - * @param readEndpointURI - URI of the read SPARQL endpoint for the knowledge base - * @param updateEndpointURI - URI of the update SPARQL endpoint for the knowledge base - * - * The default read graph is the union of all graphs in the - * knowledge base - */ - public RDFServiceSparql(String readEndpointURI, String updateEndpointURI) { - this(readEndpointURI, updateEndpointURI, null); - } - - /** - * Returns an RDFService for a remote repository - * @param endpointURI - URI of the read and update SPARQL endpoint for the knowledge base - * - * The default read graph is the union of all graphs in the - * knowledge base - */ - public RDFServiceSparql(String endpointURI) { - this(endpointURI, endpointURI, null); - } - - public void close() { - // nothing for now - } - - /** - * Perform a series of additions to and or removals from specified graphs - * in the RDF store. preConditionSparql will be executed against the - * union of all the graphs in the knowledge base before any updates are made. - * If the precondition query returns a non-empty result no updates - * will be made. - * - * @param changeSet - a set of changes to be performed on the RDF store. - * - * @return boolean - indicates whether the precondition was satisfied - */ - @Override - public boolean changeSetUpdate(ChangeSet changeSet) - throws RDFServiceException { - - if (changeSet.getPreconditionQuery() != null - && !isPreconditionSatisfied( - changeSet.getPreconditionQuery(), - changeSet.getPreconditionQueryType())) { - return false; - } - - try { - - for (Object o : changeSet.getPreChangeEvents()) { - this.notifyListenersOfEvent(o); - } - - for (ModelChange modelChange : changeSet.getModelChanges()) { - if (!modelChange.getSerializedModel().markSupported()) { - byte[] bytes = IOUtils.toByteArray(modelChange.getSerializedModel()); - modelChange.setSerializedModel(new ByteArrayInputStream(bytes)); - } - modelChange.getSerializedModel().mark(Integer.MAX_VALUE); - performChange(modelChange); - } - - notifyListenersOfChanges(changeSet); - - for (Object o : changeSet.getPostChangeEvents()) { - this.notifyListenersOfEvent(o); - } - - } catch (Exception e) { - log.error(e, e); - throw new RDFServiceException(e); - } finally { - rebuildGraphURICache = true; - } - return true; - } - - /** - * Performs a SPARQL construct query against the knowledge base. The query may have - * an embedded graph identifier. - * - * @param queryStr - the SPARQL query to be executed against the RDF store - * @param resultFormat - type of serialization for RDF result of the SPARQL query - */ - @Override - public InputStream sparqlConstructQuery(String queryStr, - RDFServiceImpl.ModelSerializationFormat resultFormat) throws RDFServiceException { - - Model model = ModelFactory.createDefaultModel(); - Query query = createQuery(queryStr); - QueryExecution qe = QueryExecutionFactory.sparqlService(readEndpointURI, query); - - try { - qe.execConstruct(model); - } catch (Exception e) { - log.error("Error executing CONSTRUCT against remote endpoint: " + queryStr); - } finally { - qe.close(); - } - - ByteArrayOutputStream serializedModel = new ByteArrayOutputStream(); - model.write(serializedModel,getSerializationFormatString(resultFormat)); - InputStream result = new ByteArrayInputStream(serializedModel.toByteArray()); - return result; - } - - public void sparqlConstructQuery(String queryStr, Model model) throws RDFServiceException { - - Query query = createQuery(queryStr); - QueryExecution qe = QueryExecutionFactory.sparqlService(readEndpointURI, query); - - try { - qe.execConstruct(model); - } catch (Exception e) { - log.error("Error executing CONSTRUCT against remote endpoint: " + queryStr); - } finally { - qe.close(); - } - } - - /** - * Performs a SPARQL describe query against the knowledge base. The query may have - * an embedded graph identifier. - * - * @param queryStr - the SPARQL query to be executed against the RDF store - * @param resultFormat - type of serialization for RDF result of the SPARQL query - * - * @return InputStream - the result of the query - * - */ - @Override - public InputStream sparqlDescribeQuery(String queryStr, - RDFServiceImpl.ModelSerializationFormat resultFormat) throws RDFServiceException { - - Model model = ModelFactory.createDefaultModel(); - Query query = createQuery(queryStr); - QueryExecution qe = QueryExecutionFactory.sparqlService(readEndpointURI, query); - - try { - qe.execDescribe(model); - } finally { - qe.close(); - } - - ByteArrayOutputStream serializedModel = new ByteArrayOutputStream(); - model.write(serializedModel,getSerializationFormatString(resultFormat)); - InputStream result = new ByteArrayInputStream(serializedModel.toByteArray()); - return result; - } - - /** - * Performs a SPARQL select query against the knowledge base. The query may have - * an embedded graph identifier. - * - * @param queryStr - the SPARQL query to be executed against the RDF store - * @param resultFormat - format for the result of the Select query - * - * @return InputStream - the result of the query - * - */ - @Override - public InputStream sparqlSelectQuery(String queryStr, RDFService.ResultFormat resultFormat) throws RDFServiceException { - - //QueryEngineHTTP qh = new QueryEngineHTTP(readEndpointURI, queryStr); - - try { - HttpGet meth = new HttpGet(new URIBuilder(readEndpointURI).addParameter("query", queryStr).build()); - meth.addHeader("Accept", "application/sparql-results+xml"); - HttpContext context = getContext(meth); - HttpResponse response = context != null ? httpClient.execute(meth, context) : httpClient.execute(meth); - try { - int statusCode = response.getStatusLine().getStatusCode(); - if (statusCode > 399) { - log.error("response " + statusCode + " to query. \n"); - log.debug("update string: \n" + queryStr); - throw new RDFServiceException("Unable to perform SPARQL SELECT"); - } - - try (InputStream in = response.getEntity().getContent()) { - ResultSet resultSet = ResultSetFactory.fromXML(in); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - switch (resultFormat) { - case CSV: - ResultSetFormatter.outputAsCSV(outputStream, resultSet); - break; - case TEXT: - ResultSetFormatter.out(outputStream, resultSet); - break; - case JSON: - ResultSetFormatter.outputAsJSON(outputStream, resultSet); - break; - case XML: - ResultSetFormatter.outputAsXML(outputStream, resultSet); - break; - default: - throw new RDFServiceException("unrecognized result format"); - } - InputStream result = new ByteArrayInputStream( - outputStream.toByteArray()); - return result; - } - } finally { - EntityUtils.consume(response.getEntity()); - } - } catch (IOException | URISyntaxException ioe) { - throw new RuntimeException(ioe); - } - } - - public void sparqlSelectQuery(String queryStr, ResultSetConsumer consumer) throws RDFServiceException { - - //QueryEngineHTTP qh = new QueryEngineHTTP(readEndpointURI, queryStr); - - try { - HttpGet meth = new HttpGet(new URIBuilder(readEndpointURI).addParameter("query", queryStr).build()); - meth.addHeader("Accept", "application/sparql-results+xml"); - HttpContext context = getContext(meth); - HttpResponse response = context != null ? httpClient.execute(meth, context) : httpClient.execute(meth); - try { - int statusCode = response.getStatusLine().getStatusCode(); - if (statusCode > 399) { - log.error("response " + statusCode + " to query. \n"); - log.debug("update string: \n" + queryStr); - throw new RDFServiceException("Unable to perform SPARQL UPDATE"); - } - - try (InputStream in = response.getEntity().getContent()) { - consumer.processResultSet(ResultSetFactory.fromXML(in)); - } - } finally { - EntityUtils.consume(response.getEntity()); - } - } catch (IOException | URISyntaxException ioe) { - throw new RuntimeException(ioe); - } - } - - /** - * Performs a SPARQL ASK query against the knowledge base. The query may have - * an embedded graph identifier. - * - * @param queryStr - the SPARQL query to be executed against the RDF store - * - * @return boolean - the result of the SPARQL query - */ - @Override - public boolean sparqlAskQuery(String queryStr) throws RDFServiceException { - - Query query = createQuery(queryStr); - QueryExecution qe = QueryExecutionFactory.sparqlService(readEndpointURI, query); - - try { - return qe.execAsk(); - } finally { - qe.close(); - } - } - - protected void rebuildGraphUris() { - Thread thread = new VitroBackgroundThread(new Runnable() { - public void run() { - synchronized (RDFServiceJena.class) { - if (rebuildGraphURICache) { - try { - isRebuildGraphURICacheRunning = true; - Set newURIs = new HashSet<>(); - try { - String fastJenaQuery = "SELECT DISTINCT ?g WHERE { GRAPH ?g {} } ORDER BY ?g"; - newURIs.addAll(getGraphURIsFromSparqlQuery(fastJenaQuery)); - } catch (Exception e) { - log.debug("Unable to use non-standard ARQ query for graph list", e); - } - if (graphURIs.isEmpty()) { - String standardQuery = "SELECT DISTINCT ?g WHERE { GRAPH ?g { ?s ?p ?o } }"; - newURIs.addAll(getGraphURIsFromSparqlQuery(standardQuery)); - } - updateGraphURIs(newURIs); - } catch (Exception e) { - log.error(e, e); - } finally { - isRebuildGraphURICacheRunning = false; - rebuildGraphURICache = false; - } - } - } - } - }, "Rebuild graphURI cache thread"); - thread.start(); - } - - private List getGraphURIsFromSparqlQuery(String queryString) throws RDFServiceException { - final List graphURIs = new ArrayList(); - try { - sparqlSelectQuery(queryString, new ResultSetConsumer() { - @Override - protected void processQuerySolution(QuerySolution qs) { - if (qs != null) { // no idea how this happens, but it seems to - RDFNode n = qs.getResource("g"); - if (n != null && n.isResource()) { - graphURIs.add(((Resource) n).getURI()); - } - } - } - }); - } catch (Exception e) { - throw new RDFServiceException("Unable to list graph URIs", e); - } - return graphURIs; - } - - /** - */ - @Override - public void getGraphMetadata() throws RDFServiceException { - throw new UnsupportedOperationException(); - } - - /** - * Get the URI of the default write graph - * - * @return String URI of default write graph - */ - @Override - public String getDefaultWriteGraphURI() throws RDFServiceException { - return defaultWriteGraphURI; - } - - /** - * Register a listener to listen to changes in any graph in - * the RDF store. - * - */ - @Override - public synchronized void registerListener(ChangeListener changeListener) throws RDFServiceException { - - if (!registeredListeners.contains(changeListener)) { - registeredListeners.add(changeListener); - } - } - - /** - * Unregister a listener from listening to changes in any graph - * in the RDF store. - * - */ - @Override - public synchronized void unregisterListener(ChangeListener changeListener) throws RDFServiceException { - registeredListeners.remove(changeListener); - } - - /** - * Create a ChangeSet object - * - * @return a ChangeSet object - */ - @Override - public ChangeSet manufactureChangeSet() { - return new ChangeSetImpl(); - } - - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // Non-override methods below - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - protected String getReadEndpointURI() { - return readEndpointURI; - } - - protected String getUpdateEndpointURI() { - return updateEndpointURI; - } - - protected void executeUpdate(String updateString) throws RDFServiceException { - try { - HttpPost meth = new HttpPost(updateEndpointURI); - meth.addHeader("Content-Type", "application/x-www-form-urlencoded; charset="+Consts.UTF_8); - meth.setEntity(new UrlEncodedFormEntity(Arrays.asList(new BasicNameValuePair("update", updateString)),Consts.UTF_8)); - HttpContext context = getContext(meth); - HttpResponse response = context != null ? httpClient.execute(meth, context) : httpClient.execute(meth); - try { - int statusCode = response.getStatusLine().getStatusCode(); - if (statusCode > 399) { - log.error("response " + response.getStatusLine() + " to update. \n"); - //log.debug("update string: \n" + updateString); - throw new RDFServiceException("Unable to perform SPARQL UPDATE"); - } - } finally { - EntityUtils.consume(response.getEntity()); - } - } catch (Exception e) { - log.debug("update string: \n" + updateString); - throw new RDFServiceException("Unable to perform change set update", e); - } - } - - private void addModel(Model model, String graphURI) throws RDFServiceException { - try { - long start = System.currentTimeMillis(); - verbModel(model, graphURI, "INSERT"); - log.info((System.currentTimeMillis() - start) + " ms to insert " + model.size() + " triples"); - } finally { - rebuildGraphURICache = true; - } - } - - private void deleteModel(Model model, String graphURI) throws RDFServiceException { - try { - verbModel(model, graphURI, "DELETE"); - } finally { - rebuildGraphURICache = true; - } - } - - private void verbModel(Model model, String graphURI, String verb) throws RDFServiceException { - Model m = ModelFactory.createDefaultModel(); - StmtIterator stmtIt = model.listStatements(); - int count = 0; - try { - while (stmtIt.hasNext()) { - count++; - m.add(stmtIt.nextStatement()); - if (count % CHUNK_SIZE == 0 || !stmtIt.hasNext()) { - StringWriter sw = new StringWriter(); - m.write(sw, "N-TRIPLE"); - StringBuilder updateStringBuff = new StringBuilder(); - updateStringBuff.append(verb).append(" DATA { ").append((graphURI != null) ? "GRAPH <" + graphURI + "> { " : ""); - updateStringBuff.append(sw); - updateStringBuff.append((graphURI != null) ? " } " : "").append(" }"); - - String updateString = updateStringBuff.toString(); - - executeUpdate(updateString); - - m.removeAll(); - } - } - } finally { - stmtIt.close(); - } - } - -// protected void addTriple(Triple t, String graphURI) throws RDFServiceException { -// try { -// StringBuffer updateString = new StringBuffer(); -// updateString.append("INSERT DATA { "); -// updateString.append((graphURI != null) ? "GRAPH <" + graphURI + "> { " : ""); -// updateString.append(sparqlNodeUpdate(t.getSubject(), "")); -// updateString.append(" "); -// updateString.append(sparqlNodeUpdate(t.getPredicate(), "")); -// updateString.append(" "); -// updateString.append(sparqlNodeUpdate(t.getObject(), "")); -// updateString.append(" }"); -// updateString.append((graphURI != null) ? " } " : ""); + private static final Log log = LogFactory.getLog(RDFServiceImpl.class); + protected String readEndpointURI; + protected String updateEndpointURI; + // the number of triples to be + private static final int CHUNK_SIZE = 5000; // added/removed in a single + // SPARQL UPDATE + + protected HttpClient httpClient; + + /** + * Returns an RDFService for a remote repository + * + * @param readEndpointURI - URI of the read SPARQL endpoint for the knowledge base + * @param updateEndpointURI - URI of the update SPARQL endpoint for the knowledge base + * @param defaultWriteGraphURI - URI of the default write graph within the knowledge base. this is the graph that + * will be written to when a graph is not explicitly specified. + * + * The default read graph is the union of all graphs in the knowledge base + */ + public RDFServiceSparql(String readEndpointURI, String updateEndpointURI, String defaultWriteGraphURI) { + this.readEndpointURI = readEndpointURI; + this.updateEndpointURI = updateEndpointURI; + httpClient = HttpClientFactory.getHttpClient(); + + if (RDFServiceSparql.class.getName().equals(this.getClass().getName())) { + testConnection(); + } + } + + protected void testConnection() { + try { + this.sparqlSelectQuery( + "SELECT ?s WHERE { ?s a " + " }", + RDFService.ResultFormat.JSON); + } catch (Exception e) { + throw new RuntimeException("Unable to connect to endpoint at " + readEndpointURI, e); + } + } + + /** + * Returns an RDFService for a remote repository + * + * @param readEndpointURI - URI of the read SPARQL endpoint for the knowledge base + * @param updateEndpointURI - URI of the update SPARQL endpoint for the knowledge base + * + * The default read graph is the union of all graphs in the knowledge base + */ + public RDFServiceSparql(String readEndpointURI, String updateEndpointURI) { + this(readEndpointURI, updateEndpointURI, null); + } + + /** + * Returns an RDFService for a remote repository + * + * @param endpointURI - URI of the read and update SPARQL endpoint for the knowledge base + * + * The default read graph is the union of all graphs in the knowledge base + */ + public RDFServiceSparql(String endpointURI) { + this(endpointURI, endpointURI, null); + } + + public void close() { + // nothing for now + } + + /** + * Perform a series of additions to and or removals from specified graphs in the RDF store. preConditionSparql will + * be executed against the union of all the graphs in the knowledge base before any updates are made. If the + * precondition query returns a non-empty result no updates will be made. + * + * @param changeSet - a set of changes to be performed on the RDF store. + * + * @return boolean - indicates whether the precondition was satisfied + */ + @Override + public boolean changeSetUpdate(ChangeSet changeSet) throws RDFServiceException { + + if (changeSet.getPreconditionQuery() != null + && !isPreconditionSatisfied(changeSet.getPreconditionQuery(), changeSet.getPreconditionQueryType())) { + return false; + } + + try { + + for (Object o : changeSet.getPreChangeEvents()) { + this.notifyListenersOfEvent(o); + } + + for (ModelChange modelChange : changeSet.getModelChanges()) { + if (!modelChange.getSerializedModel().markSupported()) { + byte[] bytes = IOUtils.toByteArray(modelChange.getSerializedModel()); + modelChange.setSerializedModel(new ByteArrayInputStream(bytes)); + } + modelChange.getSerializedModel().mark(Integer.MAX_VALUE); + performChange(modelChange); + } + + notifyListenersOfChanges(changeSet); + + for (Object o : changeSet.getPostChangeEvents()) { + this.notifyListenersOfEvent(o); + } + + } catch (Exception e) { + log.error(e, e); + throw new RDFServiceException(e); + } finally { + rebuildGraphURICache = true; + } + return true; + } + + /** + * Performs a SPARQL construct query against the knowledge base. The query may have an embedded graph identifier. + * + * @param queryStr - the SPARQL query to be executed against the RDF store + * @param resultFormat - type of serialization for RDF result of the SPARQL query + */ + @Override + public InputStream sparqlConstructQuery(String queryStr, RDFServiceImpl.ModelSerializationFormat resultFormat) + throws RDFServiceException { + + Model model = ModelFactory.createDefaultModel(); + Query query = createQuery(queryStr); + QueryExecution qe = QueryExecutionFactory.sparqlService(readEndpointURI, query); + + try { + qe.execConstruct(model); + } catch (Exception e) { + log.error("Error executing CONSTRUCT against remote endpoint: " + queryStr); + } finally { + qe.close(); + } + + ByteArrayOutputStream serializedModel = new ByteArrayOutputStream(); + model.write(serializedModel, getSerializationFormatString(resultFormat)); + InputStream result = new ByteArrayInputStream(serializedModel.toByteArray()); + return result; + } + + public void sparqlConstructQuery(String queryStr, Model model) throws RDFServiceException { + + Query query = createQuery(queryStr); + QueryExecution qe = QueryExecutionFactory.sparqlService(readEndpointURI, query); + + try { + qe.execConstruct(model); + } catch (Exception e) { + log.error("Error executing CONSTRUCT against remote endpoint: " + queryStr); + } finally { + qe.close(); + } + } + + /** + * Performs a SPARQL describe query against the knowledge base. The query may have an embedded graph identifier. + * + * @param queryStr - the SPARQL query to be executed against the RDF store + * @param resultFormat - type of serialization for RDF result of the SPARQL query + * + * @return InputStream - the result of the query + * + */ + @Override + public InputStream sparqlDescribeQuery(String queryStr, RDFServiceImpl.ModelSerializationFormat resultFormat) + throws RDFServiceException { + + Model model = ModelFactory.createDefaultModel(); + Query query = createQuery(queryStr); + QueryExecution qe = QueryExecutionFactory.sparqlService(readEndpointURI, query); + + try { + qe.execDescribe(model); + } finally { + qe.close(); + } + + ByteArrayOutputStream serializedModel = new ByteArrayOutputStream(); + model.write(serializedModel, getSerializationFormatString(resultFormat)); + InputStream result = new ByteArrayInputStream(serializedModel.toByteArray()); + return result; + } + + /** + * Performs a SPARQL select query against the knowledge base. The query may have an embedded graph identifier. + * + * @param queryStr - the SPARQL query to be executed against the RDF store + * @param resultFormat - format for the result of the Select query + * + * @return InputStream - the result of the query + * + */ + @Override + public InputStream sparqlSelectQuery(String queryStr, RDFService.ResultFormat resultFormat) + throws RDFServiceException { + + // QueryEngineHTTP qh = new QueryEngineHTTP(readEndpointURI, queryStr); + + try { + HttpGet meth = new HttpGet(new URIBuilder(readEndpointURI).addParameter("query", queryStr).build()); + meth.addHeader("Accept", "application/sparql-results+xml"); + HttpContext context = getContext(meth); + HttpResponse response = context != null ? httpClient.execute(meth, context) : httpClient.execute(meth); + try { + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode > 399) { + log.error("response " + statusCode + " to query. \n"); + log.debug("update string: \n" + queryStr); + throw new RDFServiceException("Unable to perform SPARQL SELECT"); + } + + try (InputStream in = response.getEntity().getContent()) { + ResultSet resultSet = ResultSetFactory.fromXML(in); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + switch (resultFormat) { + case CSV: + ResultSetFormatter.outputAsCSV(outputStream, resultSet); + break; + case TEXT: + ResultSetFormatter.out(outputStream, resultSet); + break; + case JSON: + ResultSetFormatter.outputAsJSON(outputStream, resultSet); + break; + case XML: + ResultSetFormatter.outputAsXML(outputStream, resultSet); + break; + default: + throw new RDFServiceException("unrecognized result format"); + } + InputStream result = new ByteArrayInputStream(outputStream.toByteArray()); + return result; + } + } finally { + EntityUtils.consume(response.getEntity()); + } + } catch (IOException | URISyntaxException ioe) { + throw new RuntimeException(ioe); + } + } + + public void sparqlSelectQuery(String queryStr, ResultSetConsumer consumer) throws RDFServiceException { + + // QueryEngineHTTP qh = new QueryEngineHTTP(readEndpointURI, queryStr); + + try { + HttpGet meth = new HttpGet(new URIBuilder(readEndpointURI).addParameter("query", queryStr).build()); + meth.addHeader("Accept", "application/sparql-results+xml"); + HttpContext context = getContext(meth); + HttpResponse response = context != null ? httpClient.execute(meth, context) : httpClient.execute(meth); + try { + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode > 399) { + log.error("response " + statusCode + " to query. \n"); + log.debug("update string: \n" + queryStr); + throw new RDFServiceException("Unable to perform SPARQL UPDATE"); + } + + try (InputStream in = response.getEntity().getContent()) { + consumer.processResultSet(ResultSetFactory.fromXML(in)); + } + } finally { + EntityUtils.consume(response.getEntity()); + } + } catch (IOException | URISyntaxException ioe) { + throw new RuntimeException(ioe); + } + } + + /** + * Performs a SPARQL ASK query against the knowledge base. The query may have an embedded graph identifier. + * + * @param queryStr - the SPARQL query to be executed against the RDF store + * + * @return boolean - the result of the SPARQL query + */ + @Override + public boolean sparqlAskQuery(String queryStr) throws RDFServiceException { + + Query query = createQuery(queryStr); + QueryExecution qe = QueryExecutionFactory.sparqlService(readEndpointURI, query); + + try { + return qe.execAsk(); + } finally { + qe.close(); + } + } + + protected void rebuildGraphUris() { + Thread thread = new VitroBackgroundThread(new Runnable() { + public void run() { + synchronized (RDFServiceJena.class) { + if (rebuildGraphURICache) { + try { + isRebuildGraphURICacheRunning = true; + Set newURIs = new HashSet<>(); + try { + String fastJenaQuery = "SELECT DISTINCT ?g WHERE { GRAPH ?g {} } ORDER BY ?g"; + newURIs.addAll(getGraphURIsFromSparqlQuery(fastJenaQuery)); + } catch (Exception e) { + log.debug("Unable to use non-standard ARQ query for graph list", e); + } + if (graphURIs.isEmpty()) { + String standardQuery = "SELECT DISTINCT ?g WHERE { GRAPH ?g { ?s ?p ?o } }"; + newURIs.addAll(getGraphURIsFromSparqlQuery(standardQuery)); + } + updateGraphURIs(newURIs); + } catch (Exception e) { + log.error(e, e); + } finally { + isRebuildGraphURICacheRunning = false; + rebuildGraphURICache = false; + } + } + } + } + }, "Rebuild graphURI cache thread"); + thread.start(); + } + + private List getGraphURIsFromSparqlQuery(String queryString) throws RDFServiceException { + final List graphURIs = new ArrayList(); + try { + sparqlSelectQuery(queryString, new ResultSetConsumer() { + @Override + protected void processQuerySolution(QuerySolution qs) { + if (qs != null) { // no idea how this happens, but it seems to + RDFNode n = qs.getResource("g"); + if (n != null && n.isResource()) { + graphURIs.add(((Resource) n).getURI()); + } + } + } + }); + } catch (Exception e) { + throw new RDFServiceException("Unable to list graph URIs", e); + } + return graphURIs; + } + + /** + */ + @Override + public void getGraphMetadata() throws RDFServiceException { + throw new UnsupportedOperationException(); + } + + /** + * Get the URI of the default write graph + * + * @return String URI of default write graph + */ + @Override + public String getDefaultWriteGraphURI() throws RDFServiceException { + return defaultWriteGraphURI; + } + + /** + * Register a listener to listen to changes in any graph in the RDF store. + * + */ + @Override + public synchronized void registerListener(ChangeListener changeListener) throws RDFServiceException { + + if (!registeredListeners.contains(changeListener)) { + registeredListeners.add(changeListener); + } + } + + /** + * Unregister a listener from listening to changes in any graph in the RDF store. + * + */ + @Override + public synchronized void unregisterListener(ChangeListener changeListener) throws RDFServiceException { + registeredListeners.remove(changeListener); + } + + /** + * Create a ChangeSet object + * + * @return a ChangeSet object + */ + @Override + public ChangeSet manufactureChangeSet() { + return new ChangeSetImpl(); + } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Non-override methods below + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + protected String getReadEndpointURI() { + return readEndpointURI; + } + + protected String getUpdateEndpointURI() { + return updateEndpointURI; + } + + protected void executeUpdate(String updateString) throws RDFServiceException { + try { + HttpPost meth = new HttpPost(updateEndpointURI); + meth.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=" + Consts.UTF_8); + meth.setEntity(new UrlEncodedFormEntity(Arrays.asList(new BasicNameValuePair("update", updateString)), + Consts.UTF_8)); + HttpContext context = getContext(meth); + HttpResponse response = context != null ? httpClient.execute(meth, context) : httpClient.execute(meth); + try { + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode > 399) { + log.error("response " + response.getStatusLine() + " to update. \n"); + // log.debug("update string: \n" + updateString); + throw new RDFServiceException("Unable to perform SPARQL UPDATE"); + } + } finally { + EntityUtils.consume(response.getEntity()); + } + } catch (Exception e) { + log.debug("update string: \n" + updateString); + throw new RDFServiceException("Unable to perform change set update", e); + } + } + + private void addModel(Model model, String graphURI) throws RDFServiceException { + try { + long start = System.currentTimeMillis(); + verbModel(model, graphURI, "INSERT"); + log.info((System.currentTimeMillis() - start) + " ms to insert " + model.size() + " triples"); + } finally { + rebuildGraphURICache = true; + } + } + + private void deleteModel(Model model, String graphURI) throws RDFServiceException { + try { + verbModel(model, graphURI, "DELETE"); + } finally { + rebuildGraphURICache = true; + } + } + + private void verbModel(Model model, String graphURI, String verb) throws RDFServiceException { + Model m = ModelFactory.createDefaultModel(); + StmtIterator stmtIt = model.listStatements(); + int count = 0; + try { + while (stmtIt.hasNext()) { + count++; + m.add(stmtIt.nextStatement()); + if (count % CHUNK_SIZE == 0 || !stmtIt.hasNext()) { + StringWriter sw = new StringWriter(); + m.write(sw, "N-TRIPLE"); + StringBuilder updateStringBuff = new StringBuilder(); + updateStringBuff.append(verb).append(" DATA { ") + .append((graphURI != null) ? "GRAPH <" + graphURI + "> { " : ""); + updateStringBuff.append(sw); + updateStringBuff.append((graphURI != null) ? " } " : "").append(" }"); + + String updateString = updateStringBuff.toString(); + + executeUpdate(updateString); + + m.removeAll(); + } + } + } finally { + stmtIt.close(); + } + } + +// protected void addTriple(Triple t, String graphURI) throws RDFServiceException { +// try { +// StringBuffer updateString = new StringBuffer(); +// updateString.append("INSERT DATA { "); +// updateString.append((graphURI != null) ? "GRAPH <" + graphURI + "> { " : ""); +// updateString.append(sparqlNodeUpdate(t.getSubject(), "")); +// updateString.append(" "); +// updateString.append(sparqlNodeUpdate(t.getPredicate(), "")); +// updateString.append(" "); +// updateString.append(sparqlNodeUpdate(t.getObject(), "")); +// updateString.append(" }"); +// updateString.append((graphURI != null) ? " } " : ""); // -// executeUpdate(updateString.toString()); -// notifyListeners(t, ModelChange.Operation.ADD, graphURI); -// } finally { -// rebuildGraphURICache = true; -// } -// } +// executeUpdate(updateString.toString()); +// notifyListeners(t, ModelChange.Operation.ADD, graphURI); +// } finally { +// rebuildGraphURICache = true; +// } +// } // -// protected void removeTriple(Triple t, String graphURI) throws RDFServiceException { -// try { -// StringBuffer updateString = new StringBuffer(); -// updateString.append("DELETE DATA { "); -// updateString.append((graphURI != null) ? "GRAPH <" + graphURI + "> { " : ""); -// updateString.append(sparqlNodeUpdate(t.getSubject(), "")); -// updateString.append(" "); -// updateString.append(sparqlNodeUpdate(t.getPredicate(), "")); -// updateString.append(" "); -// updateString.append(sparqlNodeUpdate(t.getObject(), "")); -// updateString.append(" }"); -// updateString.append((graphURI != null) ? " } " : ""); +// protected void removeTriple(Triple t, String graphURI) throws RDFServiceException { +// try { +// StringBuffer updateString = new StringBuffer(); +// updateString.append("DELETE DATA { "); +// updateString.append((graphURI != null) ? "GRAPH <" + graphURI + "> { " : ""); +// updateString.append(sparqlNodeUpdate(t.getSubject(), "")); +// updateString.append(" "); +// updateString.append(sparqlNodeUpdate(t.getPredicate(), "")); +// updateString.append(" "); +// updateString.append(sparqlNodeUpdate(t.getObject(), "")); +// updateString.append(" }"); +// updateString.append((graphURI != null) ? " } " : ""); // -// executeUpdate(updateString.toString()); -// notifyListeners(t, ModelChange.Operation.REMOVE, graphURI); -// } finally { -// rebuildGraphURICache = true; -// } -// } - - @Override - protected boolean isPreconditionSatisfied(String query, - RDFService.SPARQLQueryType queryType) - throws RDFServiceException { - Model model = ModelFactory.createDefaultModel(); - - switch (queryType) { - case DESCRIBE: - model.read(sparqlDescribeQuery(query,RDFService.ModelSerializationFormat.N3), null); - return !model.isEmpty(); - case CONSTRUCT: - model.read(sparqlConstructQuery(query,RDFService.ModelSerializationFormat.N3), null); - return !model.isEmpty(); - case SELECT: - return sparqlSelectQueryHasResults(query); - case ASK: - return sparqlAskQuery(query); - default: - throw new RDFServiceException("unrecognized SPARQL query type"); - } - } - - @Override - protected boolean sparqlSelectQueryHasResults(String queryStr) throws RDFServiceException { - - Query query = createQuery(queryStr); - QueryExecution qe = QueryExecutionFactory.sparqlService(readEndpointURI, query); - - try { - ResultSet resultSet = qe.execSelect(); - return resultSet.hasNext(); - } finally { - qe.close(); - } - } - - private void performChange(ModelChange modelChange) throws RDFServiceException { - Model model = parseModel(modelChange); - Model[] separatedModel = separateStatementsWithBlankNodes(model); - if (modelChange.getOperation() == ModelChange.Operation.ADD) { - addModel(separatedModel[1], modelChange.getGraphURI()); - addBlankNodesWithSparqlUpdate(separatedModel[0], modelChange.getGraphURI()); - } else if (modelChange.getOperation() == ModelChange.Operation.REMOVE) { - deleteModel(separatedModel[1], modelChange.getGraphURI()); - removeBlankNodesWithSparqlUpdate(separatedModel[0], modelChange.getGraphURI()); - } else { - log.error("unrecognized operation type"); - } - } - - private void addBlankNodesWithSparqlUpdate(Model model, String graphURI) - throws RDFServiceException { - updateBlankNodesWithSparqlUpdate(model, graphURI, ADD); - } - - private void removeBlankNodesWithSparqlUpdate(Model model, String graphURI) - throws RDFServiceException { - updateBlankNodesWithSparqlUpdate(model, graphURI, REMOVE); - } - - private static final boolean ADD = true; - private static final boolean REMOVE = false; - - private void updateBlankNodesWithSparqlUpdate(Model model, String graphURI, boolean add) - throws RDFServiceException { - List blankNodeStatements = new ArrayList(); - StmtIterator stmtIt = model.listStatements(); - while (stmtIt.hasNext()) { - Statement stmt = stmtIt.nextStatement(); - if (stmt.getSubject().isAnon() || stmt.getObject().isAnon()) { - blankNodeStatements.add(stmt); - } - } - - if(blankNodeStatements.size() == 0) { - return; - } - - Model blankNodeModel = ModelFactory.createDefaultModel(); - blankNodeModel.add(blankNodeStatements); - - log.debug("update model size " + model.size()); - log.debug("blank node model size " + blankNodeModel.size()); - - if (!add && blankNodeModel.size() == 1) { - log.warn("Deleting single triple with blank node: " + blankNodeModel); - log.warn("This likely indicates a problem; excessive data may be deleted."); - } - - Query rootFinderQuery = QueryFactory.create(JenaModelUtils.BNODE_ROOT_QUERY); - QueryExecution qe = QueryExecutionFactory.create(rootFinderQuery, blankNodeModel); - try { - ResultSet rs = qe.execSelect(); - while (rs.hasNext()) { - QuerySolution qs = rs.next(); - org.apache.jena.rdf.model.Resource s = qs.getResource("s"); - String treeFinder = makeDescribe(s); - Query treeFinderQuery = QueryFactory.create(treeFinder); - QueryExecution qee = QueryExecutionFactory.create(treeFinderQuery, blankNodeModel); - try { - Model tree = qee.execDescribe(); - if (s.isAnon()) { - if (add) { - addModel(tree, graphURI); - } else { - removeUsingSparqlUpdate(tree, graphURI); - } - } else { - StmtIterator sit = tree.listStatements(s, null, (RDFNode) null); - while (sit.hasNext()) { - Statement stmt = sit.nextStatement(); - RDFNode n = stmt.getObject(); - Model m2 = ModelFactory.createDefaultModel(); - if (n.isResource()) { - org.apache.jena.rdf.model.Resource s2 = - (org.apache.jena.rdf.model.Resource) n; - // now run yet another describe query - String smallerTree = makeDescribe(s2); - Query smallerTreeQuery = QueryFactory.create(smallerTree); - QueryExecution qe3 = QueryExecutionFactory.create( - smallerTreeQuery, tree); - try { - qe3.execDescribe(m2); - } finally { - qe3.close(); - } - } - m2.add(stmt); - if (add) { - addModel(m2, graphURI); - } else { - removeUsingSparqlUpdate(m2, graphURI); - } - } - } - } finally { - qee.close(); - } - } - } finally { - qe.close(); - } - } - - private void removeUsingSparqlUpdate(Model model, String graphURI) - throws RDFServiceException { - - StmtIterator stmtIt = model.listStatements(); - - if (!stmtIt.hasNext()) { - stmtIt.close(); - return; - } - - StringBuffer queryBuff = new StringBuffer(); - if (graphURI != null) { - queryBuff.append("WITH <").append(graphURI).append("> \n"); - } - queryBuff.append("DELETE { \n"); - List stmts = stmtIt.toList(); - sort(stmts); - addStatementPatterns(stmts, queryBuff, !WHERE_CLAUSE); - queryBuff.append("} WHERE { \n"); - stmtIt = model.listStatements(); - stmts = stmtIt.toList(); - sort(stmts); - addStatementPatterns(stmts, queryBuff, WHERE_CLAUSE); - queryBuff.append("} \n"); - - if(log.isDebugEnabled()) { - log.debug(queryBuff.toString()); - } - executeUpdate(queryBuff.toString()); - } - - private List sort(List stmts) { - List output = new ArrayList(); - int originalSize = stmts.size(); - if (originalSize == 1) - return stmts; - List remaining = stmts; - ConcurrentLinkedQueue subjQueue = - new ConcurrentLinkedQueue(); - for(Statement stmt : remaining) { - if(stmt.getSubject().isURIResource()) { - subjQueue.add(stmt.getSubject()); - break; - } - } - if (subjQueue.isEmpty()) { - throw new RuntimeException("No named subject in statement patterns"); - } - while(remaining.size() > 0) { - if(subjQueue.isEmpty()) { - subjQueue.add(remaining.get(0).getSubject()); - } - while(!subjQueue.isEmpty()) { - org.apache.jena.rdf.model.Resource subj = subjQueue.poll(); - List temp = new ArrayList(); - for (Statement stmt : remaining) { - if(stmt.getSubject().equals(subj)) { - output.add(stmt); - if (stmt.getObject().isResource()) { - subjQueue.add((org.apache.jena.rdf.model.Resource) stmt.getObject()); - } - } else { - temp.add(stmt); - } - } - remaining = temp; - } - } - if(output.size() != originalSize) { - throw new RuntimeException("original list size was " + originalSize + - " but sorted size is " + output.size()); - } - return output; - } - - private static final boolean WHERE_CLAUSE = true; - - private void addStatementPatterns(List stmts, StringBuffer patternBuff, boolean whereClause) { - for(Statement stmt : stmts) { - Triple t = stmt.asTriple(); - patternBuff.append(SparqlGraph.sparqlNodeDelete(t.getSubject(), null)); - patternBuff.append(" "); - patternBuff.append(SparqlGraph.sparqlNodeDelete(t.getPredicate(), null)); - patternBuff.append(" "); - patternBuff.append(SparqlGraph.sparqlNodeDelete(t.getObject(), null)); - patternBuff.append(" .\n"); - if (whereClause) { - if (t.getSubject().isBlank()) { - patternBuff.append(" FILTER(isBlank(").append(SparqlGraph.sparqlNodeDelete(t.getSubject(), null)).append(")) \n"); - } - if (t.getObject().isBlank()) { - patternBuff.append(" FILTER(isBlank(").append(SparqlGraph.sparqlNodeDelete(t.getObject(), null)).append(")) \n"); - } - } - } - } - - private String makeDescribe(org.apache.jena.rdf.model.Resource s) { - StringBuilder query = new StringBuilder("DESCRIBE <") ; - if (s.isAnon()) { - query.append("_:").append(s.getId().toString()); - } else { - query.append(s.getURI()); - } - query.append(">"); - return query.toString(); - } - - private Model parseModel(ModelChange modelChange) { - Model model = ModelFactory.createDefaultModel(); - model.read(modelChange.getSerializedModel(), null, - getSerializationFormatString(modelChange.getSerializationFormat())); - return model; - } - - @Override - public void serializeAll(OutputStream outputStream) - throws RDFServiceException { - String query = "SELECT * WHERE { GRAPH ?g {?s ?p ?o}}"; - serialize(outputStream, query); - } - - @Override - public void serializeGraph(String graphURI, OutputStream outputStream) - throws RDFServiceException { - String query = "SELECT * WHERE { GRAPH <" + graphURI + "> {?s ?p ?o}}"; - serialize(outputStream, query); - } - - private void serialize(OutputStream outputStream, String query) throws RDFServiceException { - InputStream resultStream = sparqlSelectQuery(query, RDFService.ResultFormat.JSON); - ResultSet resultSet = ResultSetFactory.fromJSON(resultStream); - if (resultSet.getResultVars().contains("g")) { - Iterator quads = new ResultSetQuadsIterator(resultSet); - RDFDataMgr.writeQuads(outputStream, quads); - } else { - Iterator triples = new ResultSetTriplesIterator(resultSet); - RDFDataMgr.writeTriples(outputStream, triples); - } - } - - /** - * The basic version. Parse the model from the file, read the model from the - * tripleStore, and ask whether they are isomorphic. - */ - @Override - public boolean isEquivalentGraph(String graphURI, InputStream serializedGraph, - ModelSerializationFormat serializationFormat) throws RDFServiceException { - Model fileModel = RDFServiceUtils.parseModel(serializedGraph, serializationFormat); - Model tripleStoreModel = new RDFServiceDataset(this).getNamedModel(graphURI); - Model fromTripleStoreModel = ModelFactory.createDefaultModel().add(tripleStoreModel); - return fileModel.isIsomorphicWith(fromTripleStoreModel); - } - - /** - * The basic version. Parse the model from the file, read the model from the - * tripleStore, and ask whether they are isomorphic. - */ - @Override - public boolean isEquivalentGraph(String graphURI, Model graph) throws RDFServiceException { - Model tripleStoreModel = new RDFServiceDataset(this).getNamedModel(graphURI); - Model fromTripleStoreModel = ModelFactory.createDefaultModel().add(tripleStoreModel); - return graph.isIsomorphicWith(fromTripleStoreModel); - } - - @Override - public boolean preferPreciseOptionals() { - return false; - } - - protected HttpContext getContext(HttpRequestBase request) { - UsernamePasswordCredentials credentials = getCredentials(); - if (credentials != null) { - try { - request.addHeader(new BasicScheme().authenticate(credentials, request, null)); - - CredentialsProvider provider = new BasicCredentialsProvider(); - provider.setCredentials(AuthScope.ANY, getCredentials()); - - BasicHttpContext context = new BasicHttpContext(); - context.setAttribute(ClientContext.CREDS_PROVIDER, provider); - return context; - } catch (AuthenticationException e) { - log.error("Unable to set credentials"); - } - } - - return new BasicHttpContext(); - } - - protected UsernamePasswordCredentials getCredentials() { - return null; - } +// executeUpdate(updateString.toString()); +// notifyListeners(t, ModelChange.Operation.REMOVE, graphURI); +// } finally { +// rebuildGraphURICache = true; +// } +// } + + @Override + protected boolean isPreconditionSatisfied(String query, RDFService.SPARQLQueryType queryType) + throws RDFServiceException { + Model model = ModelFactory.createDefaultModel(); + + switch (queryType) { + case DESCRIBE: + model.read(sparqlDescribeQuery(query, RDFService.ModelSerializationFormat.N3), null); + return !model.isEmpty(); + case CONSTRUCT: + model.read(sparqlConstructQuery(query, RDFService.ModelSerializationFormat.N3), null); + return !model.isEmpty(); + case SELECT: + return sparqlSelectQueryHasResults(query); + case ASK: + return sparqlAskQuery(query); + default: + throw new RDFServiceException("unrecognized SPARQL query type"); + } + } + + @Override + protected boolean sparqlSelectQueryHasResults(String queryStr) throws RDFServiceException { + + Query query = createQuery(queryStr); + QueryExecution qe = QueryExecutionFactory.sparqlService(readEndpointURI, query); + + try { + ResultSet resultSet = qe.execSelect(); + return resultSet.hasNext(); + } finally { + qe.close(); + } + } + + private void performChange(ModelChange modelChange) throws RDFServiceException { + Model model = parseModel(modelChange); + Model[] separatedModel = separateStatementsWithBlankNodes(model); + if (modelChange.getOperation() == ModelChange.Operation.ADD) { + addModel(separatedModel[1], modelChange.getGraphURI()); + addBlankNodesWithSparqlUpdate(separatedModel[0], modelChange.getGraphURI()); + } else if (modelChange.getOperation() == ModelChange.Operation.REMOVE) { + deleteModel(separatedModel[1], modelChange.getGraphURI()); + removeBlankNodesWithSparqlUpdate(separatedModel[0], modelChange.getGraphURI()); + } else { + log.error("unrecognized operation type"); + } + } + + private void addBlankNodesWithSparqlUpdate(Model model, String graphURI) throws RDFServiceException { + updateBlankNodesWithSparqlUpdate(model, graphURI, ADD); + } + + private void removeBlankNodesWithSparqlUpdate(Model model, String graphURI) throws RDFServiceException { + updateBlankNodesWithSparqlUpdate(model, graphURI, REMOVE); + } + + private static final boolean ADD = true; + private static final boolean REMOVE = false; + + private void updateBlankNodesWithSparqlUpdate(Model model, String graphURI, boolean add) + throws RDFServiceException { + List blankNodeStatements = new ArrayList(); + StmtIterator stmtIt = model.listStatements(); + while (stmtIt.hasNext()) { + Statement stmt = stmtIt.nextStatement(); + if (stmt.getSubject().isAnon() || stmt.getObject().isAnon()) { + blankNodeStatements.add(stmt); + } + } + + if (blankNodeStatements.size() == 0) { + return; + } + + Model blankNodeModel = ModelFactory.createDefaultModel(); + blankNodeModel.add(blankNodeStatements); + + log.debug("update model size " + model.size()); + log.debug("blank node model size " + blankNodeModel.size()); + + if (!add && blankNodeModel.size() == 1) { + log.warn("Deleting single triple with blank node: " + blankNodeModel); + log.warn("This likely indicates a problem; excessive data may be deleted."); + } + + Query rootFinderQuery = QueryFactory.create(JenaModelUtils.BNODE_ROOT_QUERY); + QueryExecution qe = QueryExecutionFactory.create(rootFinderQuery, blankNodeModel); + try { + ResultSet rs = qe.execSelect(); + while (rs.hasNext()) { + QuerySolution qs = rs.next(); + org.apache.jena.rdf.model.Resource s = qs.getResource("s"); + String treeFinder = makeDescribe(s); + Query treeFinderQuery = QueryFactory.create(treeFinder); + QueryExecution qee = QueryExecutionFactory.create(treeFinderQuery, blankNodeModel); + try { + Model tree = qee.execDescribe(); + if (s.isAnon()) { + if (add) { + addModel(tree, graphURI); + } else { + removeUsingSparqlUpdate(tree, graphURI); + } + } else { + StmtIterator sit = tree.listStatements(s, null, (RDFNode) null); + while (sit.hasNext()) { + Statement stmt = sit.nextStatement(); + RDFNode n = stmt.getObject(); + Model m2 = ModelFactory.createDefaultModel(); + if (n.isResource()) { + org.apache.jena.rdf.model.Resource s2 = (org.apache.jena.rdf.model.Resource) n; + // now run yet another describe query + String smallerTree = makeDescribe(s2); + Query smallerTreeQuery = QueryFactory.create(smallerTree); + QueryExecution qe3 = QueryExecutionFactory.create(smallerTreeQuery, tree); + try { + qe3.execDescribe(m2); + } finally { + qe3.close(); + } + } + m2.add(stmt); + if (add) { + addModel(m2, graphURI); + } else { + removeUsingSparqlUpdate(m2, graphURI); + } + } + } + } finally { + qee.close(); + } + } + } finally { + qe.close(); + } + } + + private void removeUsingSparqlUpdate(Model model, String graphURI) throws RDFServiceException { + + StmtIterator stmtIt = model.listStatements(); + + if (!stmtIt.hasNext()) { + stmtIt.close(); + return; + } + + StringBuffer queryBuff = new StringBuffer(); + if (graphURI != null) { + queryBuff.append("WITH <").append(graphURI).append("> \n"); + } + queryBuff.append("DELETE { \n"); + List stmts = stmtIt.toList(); + sort(stmts); + addStatementPatterns(stmts, queryBuff, !WHERE_CLAUSE); + queryBuff.append("} WHERE { \n"); + stmtIt = model.listStatements(); + stmts = stmtIt.toList(); + sort(stmts); + addStatementPatterns(stmts, queryBuff, WHERE_CLAUSE); + queryBuff.append("} \n"); + + if (log.isDebugEnabled()) { + log.debug(queryBuff.toString()); + } + executeUpdate(queryBuff.toString()); + } + + private List sort(List stmts) { + List output = new ArrayList(); + int originalSize = stmts.size(); + if (originalSize == 1) { + return stmts; + } + List remaining = stmts; + ConcurrentLinkedQueue subjQueue = + new ConcurrentLinkedQueue(); + for (Statement stmt : remaining) { + if (stmt.getSubject().isURIResource()) { + subjQueue.add(stmt.getSubject()); + break; + } + } + if (subjQueue.isEmpty()) { + throw new RuntimeException("No named subject in statement patterns"); + } + while (remaining.size() > 0) { + if (subjQueue.isEmpty()) { + subjQueue.add(remaining.get(0).getSubject()); + } + while (!subjQueue.isEmpty()) { + org.apache.jena.rdf.model.Resource subj = subjQueue.poll(); + List temp = new ArrayList(); + for (Statement stmt : remaining) { + if (stmt.getSubject().equals(subj)) { + output.add(stmt); + if (stmt.getObject().isResource()) { + subjQueue.add((org.apache.jena.rdf.model.Resource) stmt.getObject()); + } + } else { + temp.add(stmt); + } + } + remaining = temp; + } + } + if (output.size() != originalSize) { + throw new RuntimeException( + "original list size was " + originalSize + " but sorted size is " + output.size()); + } + return output; + } + + private static final boolean WHERE_CLAUSE = true; + + private void addStatementPatterns(List stmts, StringBuffer patternBuff, boolean whereClause) { + for (Statement stmt : stmts) { + Triple t = stmt.asTriple(); + patternBuff.append(SparqlGraph.sparqlNodeDelete(t.getSubject(), null)); + patternBuff.append(" "); + patternBuff.append(SparqlGraph.sparqlNodeDelete(t.getPredicate(), null)); + patternBuff.append(" "); + patternBuff.append(SparqlGraph.sparqlNodeDelete(t.getObject(), null)); + patternBuff.append(" .\n"); + if (whereClause) { + if (t.getSubject().isBlank()) { + patternBuff.append(" FILTER(isBlank(").append(SparqlGraph.sparqlNodeDelete(t.getSubject(), null)) + .append(")) \n"); + } + if (t.getObject().isBlank()) { + patternBuff.append(" FILTER(isBlank(").append(SparqlGraph.sparqlNodeDelete(t.getObject(), null)) + .append(")) \n"); + } + } + } + } + + private String makeDescribe(org.apache.jena.rdf.model.Resource s) { + StringBuilder query = new StringBuilder("DESCRIBE <"); + if (s.isAnon()) { + query.append("_:").append(s.getId().toString()); + } else { + query.append(s.getURI()); + } + query.append(">"); + return query.toString(); + } + + private Model parseModel(ModelChange modelChange) { + Model model = ModelFactory.createDefaultModel(); + model.read(modelChange.getSerializedModel(), null, + getSerializationFormatString(modelChange.getSerializationFormat())); + return model; + } + + @Override + public void serializeAll(OutputStream outputStream) throws RDFServiceException { + String query = "SELECT * WHERE { GRAPH ?g {?s ?p ?o}}"; + serialize(outputStream, query); + } + + @Override + public void serializeGraph(String graphURI, OutputStream outputStream) throws RDFServiceException { + String query = "SELECT * WHERE { GRAPH <" + graphURI + "> {?s ?p ?o}}"; + serialize(outputStream, query); + } + + private void serialize(OutputStream outputStream, String query) throws RDFServiceException { + InputStream resultStream = sparqlSelectQuery(query, RDFService.ResultFormat.JSON); + ResultSet resultSet = ResultSetFactory.fromJSON(resultStream); + if (resultSet.getResultVars().contains("g")) { + Iterator quads = new ResultSetQuadsIterator(resultSet); + RDFDataMgr.writeQuads(outputStream, quads); + } else { + Iterator triples = new ResultSetTriplesIterator(resultSet); + RDFDataMgr.writeTriples(outputStream, triples); + } + } + + /** + * The basic version. Parse the model from the file, read the model from the tripleStore, and ask whether they are + * isomorphic. + */ + @Override + public boolean isEquivalentGraph(String graphURI, InputStream serializedGraph, + ModelSerializationFormat serializationFormat) throws RDFServiceException { + Model fileModel = RDFServiceUtils.parseModel(serializedGraph, serializationFormat); + Model tripleStoreModel = new RDFServiceDataset(this).getNamedModel(graphURI); + Model fromTripleStoreModel = ModelFactory.createDefaultModel().add(tripleStoreModel); + return fileModel.isIsomorphicWith(fromTripleStoreModel); + } + + /** + * The basic version. Parse the model from the file, read the model from the tripleStore, and ask whether they are + * isomorphic. + */ + @Override + public boolean isEquivalentGraph(String graphURI, Model graph) throws RDFServiceException { + Model tripleStoreModel = new RDFServiceDataset(this).getNamedModel(graphURI); + Model fromTripleStoreModel = ModelFactory.createDefaultModel().add(tripleStoreModel); + return graph.isIsomorphicWith(fromTripleStoreModel); + } + + @Override + public boolean preferPreciseOptionals() { + return false; + } + + protected HttpContext getContext(HttpRequestBase request) { + UsernamePasswordCredentials credentials = getCredentials(); + if (credentials != null) { + try { + request.addHeader(new BasicScheme().authenticate(credentials, request, null)); + + CredentialsProvider provider = new BasicCredentialsProvider(); + provider.setCredentials(AuthScope.ANY, getCredentials()); + + BasicHttpContext context = new BasicHttpContext(); + context.setAttribute(ClientContext.CREDS_PROVIDER, provider); + return context; + } catch (AuthenticationException e) { + log.error("Unable to set credentials"); + } + } + + return new BasicHttpContext(); + } + + protected UsernamePasswordCredentials getCredentials() { + return null; + } } diff --git a/checkstyle-suppressions.xml b/checkstyle-suppressions.xml index 9cbcfecd2f..6bdd886f5c 100644 --- a/checkstyle-suppressions.xml +++ b/checkstyle-suppressions.xml @@ -759,13 +759,10 @@ - - - @@ -773,7 +770,6 @@ - @@ -1295,4 +1291,4 @@ - \ No newline at end of file + From a09ce2c8d813f36fb23cfd9465e6cfc6985cd85f Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Thu, 20 Jun 2024 12:35:46 +0200 Subject: [PATCH 6/6] fix: reset rebuildGraphUriCache flag at start of graphUriRebuild to avoid missed graph updates --- .../vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java | 2 +- .../vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java index eba2bda568..f8cc93a677 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/jena/RDFServiceJena.java @@ -307,6 +307,7 @@ public void run() { DatasetWrapper dw = getDatasetWrapper(); try { isRebuildGraphURICacheRunning = true; + rebuildGraphURICache = false; Dataset d = dw.getDataset(); Set newURIs = new HashSet<>(); d.begin(ReadWrite.READ); @@ -324,7 +325,6 @@ public void run() { } finally { isRebuildGraphURICacheRunning = false; dw.close(); - rebuildGraphURICache = false; } } } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java index 5457c64e2e..ed8767c559 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/rdfservice/impl/sparql/RDFServiceSparql.java @@ -378,6 +378,7 @@ public void run() { if (rebuildGraphURICache) { try { isRebuildGraphURICacheRunning = true; + rebuildGraphURICache = false; Set newURIs = new HashSet<>(); try { String fastJenaQuery = "SELECT DISTINCT ?g WHERE { GRAPH ?g {} } ORDER BY ?g"; @@ -394,7 +395,6 @@ public void run() { log.error(e, e); } finally { isRebuildGraphURICacheRunning = false; - rebuildGraphURICache = false; } } }