/*******************************************************************************
* Copyright 2012 University of Southern California
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This code was developed by the Information Integration Group as part
* of the Karma project at the Information Sciences Institute of the
* University of Southern California. For more information, publications,
* and related projects, please see: http://www.isi.edu/integration
******************************************************************************/
package edu.isi.karma.er.helper;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.eclipse.jetty.http.HttpURI;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.micromata.opengis.kml.v_2_2_0.Data;
import edu.isi.karma.util.HTTPUtil;
public class TripleStoreUtil {
private static Logger logger = LoggerFactory.getLogger(TripleStoreUtil.class);
public static final String defaultServerUrl = "http://localhost:8080/openrdf-sesame/repositories";
public static final String defaultModelsRepoUrl = "http://localhost:8080/openrdf-sesame/repositories/karma_models";
public static final String defaultDataRepoUrl = "http://localhost:8080/openrdf-sesame/repositories/karma_data";
public static final String defaultWorkbenchUrl = "http://localhost:8080/openrdf-workbench/repositories";
public static final String karma_model_repo = "karma_models";
public static final String karma_data_repo = "karma_data";
private static HashMap<String, String> mime_types;
public enum RDF_Types {
TriG,
BinaryRDF,
TriX,
N_Triples,
N_Quads,
N3,
RDF_XML,
RDF_JSON,
Turtle
}
static {
initialize();
mime_types = new HashMap<String, String>();
mime_types.put(RDF_Types.TriG.name(), "application/x-trig");
mime_types.put(RDF_Types.BinaryRDF.name(), "application/x-binary-rdf");
mime_types.put(RDF_Types.TriX.name(), "application/trix");
mime_types.put(RDF_Types.N_Triples.name(), "text/plain");
mime_types.put(RDF_Types.N_Quads.name(), "text/x-nquads");
mime_types.put(RDF_Types.N3.name(), "text/rdf+n3");
mime_types.put(RDF_Types.Turtle.name(), "application/x-turtle");
mime_types.put(RDF_Types.RDF_XML.name(), "application/rdf+xml");
mime_types.put(RDF_Types.RDF_JSON.name(), "application/rdf+json");
}
/**
* This method check for the default karma repositories in the local server
* If not, it creates them
* */
public static boolean initialize() {
boolean retVal = false;
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget;
HttpResponse response;
HttpEntity entity;
ArrayList<String> repositories = new ArrayList<String>();
try {
// query the list of repositories
httpget = new HttpGet(defaultServerUrl);
httpget.setHeader("Accept", "application/sparql-results+json, */*;q=0.5");
response = httpclient.execute(httpget);
entity = response.getEntity();
if (entity != null) {
BufferedReader buf = new BufferedReader(new InputStreamReader(entity.getContent()));
String s = buf.readLine();
StringBuffer line = new StringBuffer();
while(s != null) {
line.append(s);
s = buf.readLine();
}
JSONObject data = new JSONObject(line.toString());
JSONArray repoList = data.getJSONObject("results").getJSONArray("bindings");
int count = 0;
while(count < repoList.length()) {
JSONObject obj = repoList.getJSONObject(count++);
repositories.add(obj.optJSONObject("id").optString("value"));
}
// check for karama_models repo
if (!repositories.contains(karma_model_repo)) {
logger.info("karma_models not found");
if (create_repo(karma_model_repo, "Karma default model repository", "native")) {
retVal = true;
} else {
logger.error("Could not create repository : " + karma_model_repo);
retVal = false;
}
}
// check for karama_data repo
if (!repositories.contains(karma_data_repo)) {
logger.info("karma_data not found");
if (create_repo(karma_data_repo, "Karma default data repository", "native")) {
retVal = true;
} else {
logger.error("Could not create repository : " + karma_data_repo);
retVal = false;
}
}
}
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
}
return retVal;
}
public static boolean checkConnection(String url) {
boolean retval = false;
try {
if(url.charAt(url.length()-1) != '/') {
url = url + "/";
}
url = url + "size";
logger.info(url);
String response = HTTPUtil.executeHTTPGetRequest(url, null);
try {
int i = Integer.parseInt(response);
logger.debug("Connnection to repo : " + url + " Successful.\t Size : " + i);
retval = true;
} catch (Exception e) {
logger.error("Could not parse size of repository query result.");
}
} catch(Exception e) {
e.printStackTrace();
}
return retval;
}
/**
* This method fetches all the source names of the models from the triple store
* @param TripleStoreURL : the triple store URL
* */
public HashMap<String, ArrayList<String>> fetchModelNames(String TripleStoreURL) {
if(TripleStoreURL == null || TripleStoreURL.isEmpty()) {
TripleStoreURL = defaultServerUrl + "/" +karma_model_repo;
}
ArrayList<String> names = new ArrayList<String>();
ArrayList<String> urls = new ArrayList<String>();
if(TripleStoreURL.charAt(TripleStoreURL.length() - 1) == '/') {
TripleStoreURL = TripleStoreURL.substring(0, TripleStoreURL.length()-2);
}
logger.info("Repositoty URL : " + TripleStoreURL);
// check the connection first
if (checkConnection(TripleStoreURL)) {
logger.info("Connection Test passed");
} else {
logger.info("Failed connection test : " + TripleStoreURL);
return null;
}
try {
String queryString = "PREFIX km-dev:<http://isi.edu/integration/karma/dev#> SELECT ?y ?z where { ?x km-dev:sourceName ?y . ?x km-dev:serviceUrl ?z . } ORDER BY ?y ?z";
logger.debug("query: " + queryString);
Map<String, String> formparams = new HashMap<String, String>();
formparams.put("query", queryString);
formparams.put("queryLn", "SPARQL");
String responseString = HTTPUtil.executeHTTPPostRequest(TripleStoreURL, null, "application/sparql-results+json", formparams);
if (responseString != null) {
JSONObject models = new JSONObject(responseString);
JSONArray values = models.getJSONObject("results").getJSONArray("bindings");
int count = 0;
while(count < values.length()) {
JSONObject o = values.getJSONObject(count++);
names.add(o.getJSONObject("y").getString("value"));
urls.add(o.getJSONObject("z").getString("value"));
}
}
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
}
HashMap<String, ArrayList<String>> values = new HashMap<String, ArrayList<String>>();
values.put("model_names", names);
values.put("model_urls", urls);
return values;
}
/**
* @param fileUrl : the url of the file from where the RDF is read
* @param tripleStoreURL : the triple store URL
* @param context : The graph context for the RDF
* @param replaceFlag : Whether to replace the contents of the graph
* @param deleteSrcFile : Whether to delete the source R2RML file or not
* @param rdfType : The RDF type based on which the headers for the request are set
*
* */
private boolean saveToStore(String filePath, String tripleStoreURL, String context, boolean replaceFlag, boolean deleteSrcFile, String rdfType) {
boolean retVal = false;
URI uri = null;
HttpResponse response = null;
// check the connection first
if (checkConnection(tripleStoreURL)) {
logger.info("Connection Test passed");
} else {
logger.info("Failed connection test url : " + tripleStoreURL);
return retVal;
}
if(tripleStoreURL.charAt(tripleStoreURL.length()-1) != '/') {
tripleStoreURL += "/";
}
tripleStoreURL += "statements";
try {
URIBuilder builder = new URIBuilder(tripleStoreURL);
// initialize the http entity
HttpClient httpclient = new DefaultHttpClient();
File file = new File(filePath);
if (mime_types.get(rdfType) == null) {
throw new Exception("Could not find spefied rdf type: " + rdfType);
}
FileEntity entity = new FileEntity(file, ContentType.create(mime_types.get(rdfType), "UTF-8"));
// check if we need to specify the context
if (!replaceFlag) {
if (context == null || context.isEmpty()) {
context = "null";
} else {
context = "<" + context + ">";
builder.setParameter("baseURI", "<"+context+">");
}
builder.setParameter("context", context);
// as we dont have the context or we want to append to context
// we use HttpPost over HttpPut, for put will replace the entire repo with an empty graph
logger.info("Using POST to save rdf to triple store");
uri = builder.build();
HttpPost httpPost = new HttpPost(uri);
httpPost.setEntity(entity);
// executing the http request
response = httpclient.execute(httpPost);
}
else
{
builder.setParameter("context", "<"+context+">");
builder.setParameter("baseURI", "<"+context+">");
uri = builder.build();
// we use HttpPut to replace the context
logger.info("Using PUT to save rdf to triple store");
HttpPut httpput = new HttpPut(uri);
httpput.setEntity(entity);
// executing the http request
response = httpclient.execute(httpput);
}
logger.info("request url : " + uri.toString());
logger.info("StatusCode: " + response.getStatusLine().getStatusCode());
int code = response.getStatusLine().getStatusCode();
if(code >= 200 && code < 300) {
retVal = true;
}
if(deleteSrcFile) {
file.delete();
}
} catch (Exception e) {
e.printStackTrace();
logger.error(e.getClass().getName() + " : " + e.getMessage());
}
return retVal;
}
/**
* @param fileUrl : the url of the file from where the RDF is read
* @param tripleStoreURL : the triple store URL
* @param context : The graph context for the RDF
* @param replaceFlag : Whether to replace the contents of the graph
* deleteSrcFile default : false
* rdfType default: Turtle
*
* */
public boolean saveToStore(String filePath, String tripleStoreURL, String context, boolean replaceFlag) {
return saveToStore(filePath, tripleStoreURL, context, replaceFlag, false);
}
/**
* @param fileUrl : the url of the file from where the RDF is read
*
* Default_Parameters <br />
* tripleStoreURL : the local triple store URL
* context : null
* rdfType : Turtle
* deleteSrcFile : False (will retain the source file)
* replaceFlag : true
*
* */
public boolean saveToStore(String fileUrl) {
return saveToStore(fileUrl,defaultServerUrl + "/" + karma_model_repo, null, true);
}
/**
* @param fileUrl : the url of the file from where the RDF is read
* @param tripleStoreURL : the triple store URL
* @param context : The graph context for the RDF
* @param replaceFlag : Whether to replace the contents of the graph
* @param deleteSrcFile : Whether to delete the source R2RML file or not
*
* rdfType default : Turtle
*
* */
public boolean saveToStore(String filePath, String tripleStoreURL, String context, boolean replaceFlag, boolean deleteSrcFile) {
return saveToStore(filePath, tripleStoreURL, context, replaceFlag, deleteSrcFile, RDF_Types.Turtle.name());
}
/**
* Invokes a SPARQL query on the given Triple Store URL and returns the JSON object
* containing the result. The content type of the result is application/sparql-results+json.
*
* @param query: SPARQL query
* @param tripleStoreUrl: SPARQL endpoint address of the triple store
* @param acceptContentType: The accept context type in the header
* @param contextType:
* @return
* @throws ClientProtocolException
* @throws IOException
* @throws JSONException
*/
public static String invokeSparqlQuery(String query, String tripleStoreUrl,
String acceptContentType, String contextType) throws ClientProtocolException, IOException, JSONException {
Map<String, String> formParams = new HashMap<String, String>();
formParams.put("query", query);
formParams.put("queryLn", "SPARQL");
String response = HTTPUtil.executeHTTPPostRequest(tripleStoreUrl,
contextType, acceptContentType, formParams);
if (response == null || response.isEmpty()) return null;
return response;
}
public static boolean create_repo(String repo_name, String repo_desc, String type ) {
// TODO : Take the repository type as an enum - native, memory, etc
boolean retVal = false;
if (repo_name == null || repo_name.isEmpty() ) {
logger.error("Invalid repo name : " + repo_name);
return retVal;
}
if (repo_desc == null || repo_desc.isEmpty()) {
repo_desc = repo_name;
}
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response;
try {
HttpPost httppost = new HttpPost(defaultWorkbenchUrl+"/NONE/create");
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
formparams.add(new BasicNameValuePair("Repository ID",repo_name));
formparams.add(new BasicNameValuePair("Repository title",repo_name));
formparams.add(new BasicNameValuePair("Triple indexes","spoc,posc"));
formparams.add(new BasicNameValuePair("type","native"));
httppost.setEntity(new UrlEncodedFormEntity(formparams, "UTF-8"));
httppost.setHeader("Content-Type", "application/x-www-form-urlencoded");
response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
if (entity != null) {
StringBuffer out = new StringBuffer();
BufferedReader buf = new BufferedReader(new InputStreamReader(entity.getContent()));
String line = buf.readLine();
while(line != null) {
logger.info(line);
out.append(line);
line = buf.readLine();
}
logger.info(out.toString());
}
int status = response.getStatusLine().getStatusCode();
if ( status >= 200 || status < 300) {
logger.info("Created repository : " + repo_name);
retVal = true;
}
} catch (Exception e) {
e.printStackTrace();
}
return retVal;
}
public org.json.JSONObject fetch_data(String graph, String tripleStoreUrl) throws ClientProtocolException, IOException, JSONException {
if (tripleStoreUrl == null || tripleStoreUrl.isEmpty()) {
tripleStoreUrl = defaultDataRepoUrl;
}
JSONObject retVal = new JSONObject();
StringBuffer queryString = new StringBuffer();
queryString.append("SELECT ?x ?z ")
.append("WHERE { GRAPH <").append(graph.trim()).append("> { ")
.append("?x ?p <http://isi.edu/integration/karma/ontologies/model/current/Input> . "
+ "?x <http://isi.edu/integration/karma/ontologies/model/current/hasValue> ?z . } }");
String sData = invokeSparqlQuery(queryString.toString(), tripleStoreUrl, "application/sparql-results+json", null);
if (sData == null | sData.isEmpty()) {
logger.error("Enpty response object from query : " + queryString.toString());
}
JSONObject data = new JSONObject(sData);
JSONArray d1 = data.getJSONObject("results").getJSONArray("bindings");
int count = 0;
HashMap<String, ArrayList<String>> results = new HashMap<String, ArrayList<String>>();
while(count < d1.length()) {
JSONObject obj = d1.getJSONObject(count++);
String key = obj.getJSONObject("x").getString("value");
String val = obj.getJSONObject("z").getString("value");
if (!results.keySet().contains(key)) {
results.put(key, new ArrayList<String>());
}
results.get(key).add(val);
}
return new JSONObject(results);
}
/**
* This method fetches all the context from the given triplestore Url
* */
public ArrayList<String> getContexts(String url) {
if(url==null || url.isEmpty()) {
url = defaultModelsRepoUrl;
}
url += "/contexts";
ArrayList<String> graphs = new ArrayList<String>();
String responseString;
try {
responseString = HTTPUtil.executeHTTPGetRequest(url, "application/sparql-results+json");
if (responseString != null) {
JSONObject models = new JSONObject(responseString);
JSONArray values = models.getJSONObject("results").getJSONArray("bindings");
int count = 0;
while(count < values.length()) {
JSONObject o = values.getJSONObject(count++);
graphs.add(o.getJSONObject("contextID").getString("value"));
}
}
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
graphs = null;
}
return graphs;
}
public boolean isUniqueGraphUri(String tripleStoreUrl, String graphUrl) {
logger.info("Checking for unique graphUri for url : " + graphUrl + " at endPoint : " + tripleStoreUrl);
boolean retVal = true;
ArrayList<String> urls = this.getContexts(tripleStoreUrl);
if(urls == null ){
return false;
}
// need to compare each url in case-insensitive form
for(String url : urls) {
if (url.equalsIgnoreCase(graphUrl)) {
retVal = false;
break;
}
}
return retVal;
}
}