Allow SPRAQL endpoint to have credentials on read as well as write; update Virtuoso normalisation of types
This commit is contained in:
parent
817e90716c
commit
15bc18b69a
4 changed files with 731 additions and 605 deletions
File diff suppressed because it is too large
Load diff
|
@ -6,20 +6,26 @@ import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.httpclient.HttpMethod;
|
import com.hp.hpl.jena.rdf.model.Model;
|
||||||
|
import com.hp.hpl.jena.rdf.model.ModelFactory;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Property;
|
||||||
|
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Resource;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Selector;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Statement;
|
||||||
|
import com.hp.hpl.jena.rdf.model.StmtIterator;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.dao.jena.RDFServiceDataset;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.impl.RDFServiceUtils;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.auth.AuthScope;
|
|
||||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||||
import org.apache.http.client.CredentialsProvider;
|
|
||||||
import org.apache.http.client.methods.HttpPost;
|
import org.apache.http.client.methods.HttpPost;
|
||||||
import org.apache.http.client.protocol.ClientContext;
|
|
||||||
import org.apache.http.entity.StringEntity;
|
import org.apache.http.entity.StringEntity;
|
||||||
import org.apache.http.impl.client.BasicCredentialsProvider;
|
|
||||||
import org.apache.http.protocol.BasicHttpContext;
|
|
||||||
import org.apache.http.protocol.HttpContext;
|
import org.apache.http.protocol.HttpContext;
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
|
||||||
|
@ -53,10 +59,10 @@ public class RDFServiceVirtuoso extends RDFServiceSparql {
|
||||||
private final String password;
|
private final String password;
|
||||||
|
|
||||||
public RDFServiceVirtuoso(String baseURI, String username, String password) {
|
public RDFServiceVirtuoso(String baseURI, String username, String password) {
|
||||||
super(figureReadEndpointUri(baseURI), figureUpdateEndpointUri(baseURI,
|
super(figureReadEndpointUri(baseURI), figureUpdateEndpointUri(baseURI, username));
|
||||||
username));
|
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
|
testConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String figureReadEndpointUri(String baseUri) {
|
private static String figureReadEndpointUri(String baseUri) {
|
||||||
|
@ -81,8 +87,8 @@ public class RDFServiceVirtuoso extends RDFServiceSparql {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
HttpPost request = createHttpRequest(updateString);
|
HttpPost request = createHttpRequest(updateString);
|
||||||
HttpResponse response = httpClient.execute(
|
HttpContext context = getContext(request);
|
||||||
request, createHttpContext());
|
HttpResponse response = context != null ? httpClient.execute(request, context) : httpClient.execute(request);
|
||||||
try {
|
try {
|
||||||
int statusCode = response.getStatusLine().getStatusCode();
|
int statusCode = response.getStatusLine().getStatusCode();
|
||||||
if (statusCode > 399) {
|
if (statusCode > 399) {
|
||||||
|
@ -129,18 +135,29 @@ public class RDFServiceVirtuoso extends RDFServiceSparql {
|
||||||
return meth;
|
return meth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected UsernamePasswordCredentials getCredentials() {
|
||||||
* We need an HttpContext that will provide username and password in
|
if (username != null && password != null) {
|
||||||
* response to a basic authentication challenge.
|
return new UsernamePasswordCredentials(username, password);
|
||||||
*/
|
}
|
||||||
private HttpContext createHttpContext() {
|
|
||||||
CredentialsProvider provider = new BasicCredentialsProvider();
|
|
||||||
provider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(
|
|
||||||
username, password));
|
|
||||||
|
|
||||||
BasicHttpContext context = new BasicHttpContext();
|
return null;
|
||||||
context.setAttribute(ClientContext.CREDS_PROVIDER, provider);
|
}
|
||||||
return context;
|
|
||||||
|
private static boolean isNumeric(String typeUri) {
|
||||||
|
return typeUri != null && (typeUri.endsWith("decimal") ||
|
||||||
|
typeUri.endsWith("int") ||
|
||||||
|
typeUri.endsWith("integer") ||
|
||||||
|
typeUri.endsWith("float") ||
|
||||||
|
typeUri.endsWith("long") ||
|
||||||
|
typeUri.endsWith("negativeInteger") ||
|
||||||
|
typeUri.endsWith("nonNegativeInteger") ||
|
||||||
|
typeUri.endsWith("nonPositiveInteger") ||
|
||||||
|
typeUri.endsWith("positiveInteger") ||
|
||||||
|
typeUri.endsWith("short") ||
|
||||||
|
typeUri.endsWith("unsignedLong") ||
|
||||||
|
typeUri.endsWith("unsignedInt") ||
|
||||||
|
typeUri.endsWith("unsignedShort") ||
|
||||||
|
typeUri.endsWith("unsignedByte"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -150,14 +167,84 @@ public class RDFServiceVirtuoso extends RDFServiceSparql {
|
||||||
* To determine whether this serialized graph is equivalent to what is
|
* To determine whether this serialized graph is equivalent to what is
|
||||||
* already in Virtuoso, we need to do the same.
|
* already in Virtuoso, we need to do the same.
|
||||||
*/
|
*/
|
||||||
@Override
|
public boolean isEquivalentGraph(String graphURI, InputStream serializedGraph,
|
||||||
public boolean isEquivalentGraph(String graphURI,
|
ModelSerializationFormat serializationFormat) throws RDFServiceException {
|
||||||
InputStream serializedGraph,
|
Model fileModel = RDFServiceUtils.parseModel(serializedGraph, serializationFormat);
|
||||||
ModelSerializationFormat serializationFormat)
|
Model tripleStoreModel = new RDFServiceDataset(this).getNamedModel(graphURI);
|
||||||
throws RDFServiceException {
|
Model fromTripleStoreModel = ModelFactory.createDefaultModel().add(tripleStoreModel);
|
||||||
return super.isEquivalentGraph(graphURI,
|
|
||||||
adjustForNonNegativeIntegers(serializedGraph),
|
// Compare the models
|
||||||
serializationFormat);
|
Model difference = fileModel.difference(fromTripleStoreModel);
|
||||||
|
|
||||||
|
// If there is a difference
|
||||||
|
if (difference.size() > 0) {
|
||||||
|
// First, normalize the numeric values, as Virtuoso likes to mess with the datatypes
|
||||||
|
// Iterate over the differences
|
||||||
|
StmtIterator stmtIterator = difference.listStatements();
|
||||||
|
while (stmtIterator.hasNext()) {
|
||||||
|
final Statement stmt = stmtIterator.next();
|
||||||
|
final RDFNode subject = stmt.getSubject();
|
||||||
|
final Property predicate = stmt.getPredicate();
|
||||||
|
final RDFNode object = stmt.getObject();
|
||||||
|
|
||||||
|
// If the object is a numeric literal
|
||||||
|
if (object.isLiteral() && isNumeric(object.asLiteral().getDatatypeURI())) {
|
||||||
|
// Find a matching statement in the triple store, based on normalized numeric values
|
||||||
|
StmtIterator matching = fromTripleStoreModel.listStatements(new Selector() {
|
||||||
|
@Override
|
||||||
|
public boolean test(Statement statement) {
|
||||||
|
RDFNode objectToMatch = statement.getObject();
|
||||||
|
|
||||||
|
// Both values are numeric, so compare them as parsed doubles
|
||||||
|
if (objectToMatch.isLiteral()) {
|
||||||
|
String num1 = object.asLiteral().getString();
|
||||||
|
String num2 = objectToMatch.asLiteral().getString();
|
||||||
|
|
||||||
|
return Double.parseDouble(num1) == Double.parseDouble(num2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSimple() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Resource getSubject() {
|
||||||
|
return subject.asResource();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Property getPredicate() {
|
||||||
|
return predicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RDFNode getObject() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// For every matching statement
|
||||||
|
// Rewrite the object as the one in the file model (they are the same, just differ in datatype)
|
||||||
|
List<Statement> toModify = new ArrayList<Statement>();
|
||||||
|
while (matching.hasNext()) {
|
||||||
|
toModify.add(matching.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Statement stmtToModify : toModify) {
|
||||||
|
stmtToModify.changeObject(object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we've normalized the datatypes, check the graphs are isomorphic
|
||||||
|
return fileModel.isIsomorphicWith(fromTripleStoreModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -12,6 +12,7 @@ import java.net.UnknownHostException;
|
||||||
import javax.servlet.ServletContextEvent;
|
import javax.servlet.ServletContextEvent;
|
||||||
import javax.servlet.ServletContextListener;
|
import javax.servlet.ServletContextListener;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.http.HttpClientFactory;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.http.HttpException;
|
import org.apache.http.HttpException;
|
||||||
|
@ -24,6 +25,7 @@ import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
||||||
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
|
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread;
|
import edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread;
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spin off a thread that will try to connect to Solr.
|
* Spin off a thread that will try to connect to Solr.
|
||||||
|
@ -207,7 +209,7 @@ public class SolrSmokeTest implements ServletContextListener {
|
||||||
private static final long SLEEP_INTERVAL = 20000; // 20 seconds
|
private static final long SLEEP_INTERVAL = 20000; // 20 seconds
|
||||||
|
|
||||||
private final URL solrUrl;
|
private final URL solrUrl;
|
||||||
private final HttpClient httpClient = new DefaultHttpClient();
|
private final HttpClient httpClient = HttpClientFactory.getHttpClient();
|
||||||
|
|
||||||
private int statusCode;
|
private int statusCode;
|
||||||
|
|
||||||
|
@ -238,8 +240,12 @@ public class SolrSmokeTest implements ServletContextListener {
|
||||||
HttpGet method = new HttpGet(solrUrl.toExternalForm());
|
HttpGet method = new HttpGet(solrUrl.toExternalForm());
|
||||||
SolrSmokeTest.log.debug("Trying to connect to Solr");
|
SolrSmokeTest.log.debug("Trying to connect to Solr");
|
||||||
HttpResponse response = httpClient.execute(method);
|
HttpResponse response = httpClient.execute(method);
|
||||||
statusCode = response.getStatusLine().getStatusCode();
|
try {
|
||||||
SolrSmokeTest.log.debug("HTTP status was " + statusCode);
|
statusCode = response.getStatusLine().getStatusCode();
|
||||||
|
SolrSmokeTest.log.debug("HTTP status was " + statusCode);
|
||||||
|
} finally {
|
||||||
|
EntityUtils.consume(response.getEntity());
|
||||||
|
}
|
||||||
} catch (SocketTimeoutException e) {
|
} catch (SocketTimeoutException e) {
|
||||||
// Catch the exception so we can retry this.
|
// Catch the exception so we can retry this.
|
||||||
// Save the status so we know why we failed.
|
// Save the status so we know why we failed.
|
||||||
|
@ -274,7 +280,7 @@ public class SolrSmokeTest implements ServletContextListener {
|
||||||
*/
|
*/
|
||||||
private static class SolrPinger {
|
private static class SolrPinger {
|
||||||
private final URL solrUrl;
|
private final URL solrUrl;
|
||||||
private final HttpClient httpClient = new DefaultHttpClient();
|
private final HttpClient httpClient = HttpClientFactory.getHttpClient();
|
||||||
|
|
||||||
public SolrPinger(URL solrUrl) {
|
public SolrPinger(URL solrUrl) {
|
||||||
this.solrUrl = solrUrl;
|
this.solrUrl = solrUrl;
|
||||||
|
@ -286,10 +292,14 @@ public class SolrSmokeTest implements ServletContextListener {
|
||||||
+ "/admin/ping");
|
+ "/admin/ping");
|
||||||
SolrSmokeTest.log.debug("Trying to ping Solr");
|
SolrSmokeTest.log.debug("Trying to ping Solr");
|
||||||
HttpResponse response = httpClient.execute(method);
|
HttpResponse response = httpClient.execute(method);
|
||||||
SolrSmokeTest.log.debug("Finished pinging Solr");
|
try {
|
||||||
int statusCode = response.getStatusLine().getStatusCode();
|
SolrSmokeTest.log.debug("Finished pinging Solr");
|
||||||
if (statusCode != HttpStatus.SC_OK) {
|
int statusCode = response.getStatusLine().getStatusCode();
|
||||||
throw new SolrProblemException(statusCode);
|
if (statusCode != HttpStatus.SC_OK) {
|
||||||
|
throw new SolrProblemException(statusCode);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
EntityUtils.consume(response.getEntity());
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new SolrProblemException(e);
|
throw new SolrProblemException(e);
|
||||||
|
|
|
@ -18,12 +18,14 @@ import javax.servlet.ServletContext;
|
||||||
import javax.servlet.ServletContextEvent;
|
import javax.servlet.ServletContextEvent;
|
||||||
import javax.servlet.ServletContextListener;
|
import javax.servlet.ServletContextListener;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.http.HttpClientFactory;
|
||||||
import org.apache.commons.dbcp.BasicDataSource;
|
import org.apache.commons.dbcp.BasicDataSource;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
|
import org.apache.http.client.HttpClient;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.http.client.methods.HttpGet;
|
||||||
import org.apache.http.impl.client.DefaultHttpClient;
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
|
|
||||||
|
@ -349,7 +351,7 @@ public class OpenSocialSmokeTests implements ServletContextListener {
|
||||||
|
|
||||||
private final String shindigBaseUrl;
|
private final String shindigBaseUrl;
|
||||||
private final String shindigTestUrl;
|
private final String shindigTestUrl;
|
||||||
private final DefaultHttpClient httpClient = new DefaultHttpClient();
|
private final HttpClient httpClient = HttpClientFactory.getHttpClient();
|
||||||
|
|
||||||
private int statusCode = Integer.MIN_VALUE;
|
private int statusCode = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue