VIVO-1025 Improvements to the Virtuoso driver.
This commit is contained in:
parent
586fa09666
commit
0b79dfdf01
5 changed files with 179 additions and 45 deletions
|
@ -27,6 +27,7 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.ChangeSet;
|
|||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString;
|
||||
|
||||
public class RDFServiceGraphBulkUpdater implements BulkUpdateHandler {
|
||||
private static final Log log = LogFactory.getLog(RDFServiceGraphBulkUpdater.class);
|
||||
|
@ -203,7 +204,8 @@ public class RDFServiceGraphBulkUpdater implements BulkUpdateHandler {
|
|||
|
||||
private static void removeAll(Graph g, Node s, Node p, Node o)
|
||||
{
|
||||
log.debug("removeAll: g=" + g + ", s=" + s + ", p=" + p + ", o=" + o);
|
||||
log.debug("removeAll: g=" + ToString.graphToString(g) + ", s=" + s
|
||||
+ ", p=" + p + ", o=" + o);
|
||||
if (!(g instanceof RDFServiceGraph)) {
|
||||
removeAllTripleByTriple(g, s, p, o);
|
||||
return;
|
||||
|
|
|
@ -70,7 +70,7 @@ public class RDFServiceSparql extends RDFServiceImpl implements RDFService {
|
|||
private static final Log log = LogFactory.getLog(RDFServiceImpl.class);
|
||||
protected String readEndpointURI;
|
||||
protected String updateEndpointURI;
|
||||
private CloseableHttpClient httpClient;
|
||||
protected CloseableHttpClient httpClient;
|
||||
// the number of triples to be
|
||||
private static final int CHUNK_SIZE = 1000; // added/removed in a single
|
||||
// SPARQL UPDATE
|
||||
|
@ -467,7 +467,7 @@ public class RDFServiceSparql extends RDFServiceImpl implements RDFService {
|
|||
try {
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
if (statusCode > 399) {
|
||||
log.error("response " + statusCode + " to update. \n");
|
||||
log.error("response " + response.getStatusLine() + " to update. \n");
|
||||
//log.debug("update string: \n" + updateString);
|
||||
throw new RDFServiceException("Unable to perform SPARQL UPDATE");
|
||||
}
|
||||
|
|
|
@ -7,41 +7,132 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||
import org.apache.http.client.CredentialsProvider;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.protocol.HttpClientContext;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.BasicCredentialsProvider;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
|
||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.sparql.RDFServiceSparql;
|
||||
|
||||
/**
|
||||
* For now, at least, it is just like an RDFServiceSparql except for:
|
||||
* For now, at least, it is just like an RDFServiceSparql except:
|
||||
*
|
||||
* A small change in the syntax of an UPDATE request.
|
||||
* A username and password are required. These should refer to a Virtuoso user
|
||||
* that posesses the SPARQL_UPDATE role.
|
||||
*
|
||||
* The endpoint URI and the update endpoint URI are derived from the base URI.
|
||||
* You provide: http://localhost:8890
|
||||
* endpoint is: http://localhost:8890/sparql/
|
||||
* update is: http://localhost:8890/DAV/home/username/rdf_sink/vitro_update
|
||||
*
|
||||
* A change in the syntax of an UPDATE request: "INSERT DATA" becomes "INSERT".
|
||||
* This fixes a problem with inserting blank nodes.
|
||||
*
|
||||
* The HTTP request is equipped with the username and password, to answer a
|
||||
* challenge for basic authentication.
|
||||
*
|
||||
* Allow for the nonNegativeInteger bug when checking to see whether a graph has
|
||||
* changed.
|
||||
*/
|
||||
public class RDFServiceVirtuoso extends RDFServiceSparql {
|
||||
private static final Log log = LogFactory.getLog(RDFServiceVirtuoso.class);
|
||||
|
||||
public RDFServiceVirtuoso(String readEndpointURI, String updateEndpointURI,
|
||||
String defaultWriteGraphURI) {
|
||||
super(readEndpointURI, updateEndpointURI, defaultWriteGraphURI);
|
||||
private final String username;
|
||||
private final String password;
|
||||
|
||||
public RDFServiceVirtuoso(String baseURI, String username, String password) {
|
||||
super(figureReadEndpointUri(baseURI), figureUpdateEndpointUri(baseURI,
|
||||
username));
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public RDFServiceVirtuoso(String readEndpointURI, String updateEndpointURI) {
|
||||
super(readEndpointURI, updateEndpointURI);
|
||||
private static String figureReadEndpointUri(String baseUri) {
|
||||
return noTrailingSlash(baseUri) + "/sparql/";
|
||||
}
|
||||
|
||||
public RDFServiceVirtuoso(String endpointURI) {
|
||||
super(endpointURI);
|
||||
private static String figureUpdateEndpointUri(String baseUri,
|
||||
String username) {
|
||||
return noTrailingSlash(baseUri) + "/DAV/home/" + username
|
||||
+ "/rdf_sink/vitro_update";
|
||||
}
|
||||
|
||||
private static String noTrailingSlash(String uri) {
|
||||
return uri.endsWith("/") ? uri.substring(0, uri.length() - 1) : uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void executeUpdate(String updateString)
|
||||
throws RDFServiceException {
|
||||
super.executeUpdate(updateString.replace("INSERT DATA", "INSERT"));
|
||||
updateString = tweakUpdateStringSyntax(updateString);
|
||||
log.debug("UPDATE STRING: " + updateString);
|
||||
|
||||
try {
|
||||
CloseableHttpResponse response = httpClient.execute(
|
||||
createHttpRequest(updateString), createHttpContext());
|
||||
try {
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
if (statusCode > 399) {
|
||||
log.error("response " + response.getStatusLine()
|
||||
+ " to update. \n");
|
||||
|
||||
InputStream content = response.getEntity().getContent();
|
||||
for (String line : IOUtils.readLines(content)) {
|
||||
log.error("response-line >>" + line);
|
||||
}
|
||||
|
||||
throw new RDFServiceException(
|
||||
"Unable to perform SPARQL UPDATE: status code = "
|
||||
+ statusCode);
|
||||
}
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to update: " + updateString, e);
|
||||
throw new RDFServiceException(
|
||||
"Unable to perform change set update", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String tweakUpdateStringSyntax(String updateString) {
|
||||
if (updateString.startsWith("INSERT DATA")) {
|
||||
return updateString.replaceFirst("INSERT DATA", "INSERT");
|
||||
}
|
||||
return updateString;
|
||||
}
|
||||
|
||||
// TODO entity.setContentType("application/sparql-query");
|
||||
private HttpPost createHttpRequest(String updateString) {
|
||||
HttpPost meth = new HttpPost(updateEndpointURI);
|
||||
meth.addHeader("Content-Type", "application/sparql-query");
|
||||
meth.setEntity(new StringEntity(updateString, "UTF-8"));
|
||||
return meth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Virtuoso has a bug, which it shares with TDB: if given a literal of type
|
||||
* We need an HttpContext that will provide username and password in
|
||||
* response to a basic authentication challenge.
|
||||
*/
|
||||
private HttpClientContext createHttpContext() {
|
||||
CredentialsProvider provider = new BasicCredentialsProvider();
|
||||
provider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(
|
||||
username, password));
|
||||
|
||||
HttpClientContext context = HttpClientContext.create();
|
||||
context.setCredentialsProvider(provider);
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Virtuoso has a bug which it shares with TDB: if given a literal of type
|
||||
* xsd:nonNegativeInteger, it stores a literal of type xsd:integer.
|
||||
*
|
||||
* To determine whether this serialized graph is equivalent to what is
|
||||
|
|
|
@ -73,22 +73,20 @@ public class ContentTripleSourceSPARQL extends ContentTripleSource {
|
|||
|
||||
@Override
|
||||
public void startup(Application application, ComponentStartupStatus ss) {
|
||||
this.rdfServiceFactory = createRDFServiceFactory(createRDFService(ss,
|
||||
endpointURI, updateEndpointURI));
|
||||
this.rdfServiceFactory = createRDFServiceFactory(createRDFService(ss));
|
||||
this.rdfService = this.rdfServiceFactory.getRDFService();
|
||||
this.dataset = createDataset();
|
||||
this.modelMaker = createModelMaker();
|
||||
}
|
||||
|
||||
protected RDFService createRDFService(ComponentStartupStatus ss,
|
||||
String endpoint, String updateEndpoint) {
|
||||
if (updateEndpoint == null) {
|
||||
ss.info("Using endpoint at " + endpoint);
|
||||
return new RDFServiceSparql(endpoint);
|
||||
protected RDFService createRDFService(ComponentStartupStatus ss) {
|
||||
if (updateEndpointURI == null) {
|
||||
ss.info("Using endpoint at " + endpointURI);
|
||||
return new RDFServiceSparql(endpointURI);
|
||||
} else {
|
||||
ss.info("Using read endpoint at " + endpoint
|
||||
+ " and update endpoint at " + updateEndpoint);
|
||||
return new RDFServiceSparql(endpoint, updateEndpoint);
|
||||
ss.info("Using read endpoint at " + endpointURI
|
||||
+ " and update endpoint at " + updateEndpointURI);
|
||||
return new RDFServiceSparql(endpointURI, updateEndpointURI);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,36 +7,79 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
|||
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.virtuoso.RDFServiceVirtuoso;
|
||||
import edu.cornell.mannlib.vitro.webapp.triplesource.impl.sparql.ContentTripleSourceSPARQL;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Property;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString;
|
||||
|
||||
/**
|
||||
* So far, it's just like a ContentTripleSourceSPARQL but it uses an instance of
|
||||
* RDFServiceVirtuoso.
|
||||
*/
|
||||
public class ContentTripleSourceVirtuoso extends ContentTripleSourceSPARQL {
|
||||
private String baseUri;
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
@Override
|
||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasEndpointURI")
|
||||
public void setEndpointURI(String eUri) {
|
||||
super.setEndpointURI(eUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasUpdateEndpointURI")
|
||||
public void setUpdateEndpointURI(String ueUri) {
|
||||
super.setUpdateEndpointURI(ueUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RDFService createRDFService(ComponentStartupStatus ss,
|
||||
String endpoint, String updateEndpoint) {
|
||||
if (updateEndpoint == null) {
|
||||
ss.info("Using endpoint at " + endpoint);
|
||||
return new RDFServiceVirtuoso(endpoint);
|
||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasBaseURI")
|
||||
public void setBaseUri(String uri) {
|
||||
if (baseUri == null) {
|
||||
baseUri = uri;
|
||||
} else {
|
||||
ss.info("Using read endpoint at " + endpoint
|
||||
+ " and update endpoint at " + updateEndpoint);
|
||||
return new RDFServiceVirtuoso(endpoint, updateEndpoint);
|
||||
throw new IllegalStateException(
|
||||
"Configuration includes multiple instances of BaseURI: "
|
||||
+ baseUri + ", and " + uri);
|
||||
}
|
||||
}
|
||||
|
||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasUsername")
|
||||
public void setUsername(String user) {
|
||||
if (username == null) {
|
||||
username = user;
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
"Configuration includes multiple instances of Username: "
|
||||
+ username + ", and " + user);
|
||||
}
|
||||
}
|
||||
|
||||
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasPassword")
|
||||
public void setPassword(String pass) {
|
||||
if (password == null) {
|
||||
password = pass;
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
"Configuration includes multiple instances of Password: "
|
||||
+ password + ", and " + pass);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Validation
|
||||
public void validate() throws Exception {
|
||||
if (baseUri == null) {
|
||||
throw new IllegalStateException(
|
||||
"Configuration did not include a BaseURI.");
|
||||
}
|
||||
if (username == null) {
|
||||
throw new IllegalStateException(
|
||||
"Configuration did not include a Username.");
|
||||
}
|
||||
if (password == null) {
|
||||
throw new IllegalStateException(
|
||||
"Configuration did not include a Password.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RDFService createRDFService(ComponentStartupStatus ss) {
|
||||
ss.info("Using Virtuoso at " + baseUri + ", authenticating as "
|
||||
+ username);
|
||||
return new RDFServiceVirtuoso(baseUri, username, password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ContentTripleSourceVirtuoso[" + ToString.hashHex(this)
|
||||
+ ", baseUri=" + baseUri + ", username=" + username + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue