edu.cornell.mannlib.vitro.webapp.dao.jena.SparqlGraph.java Source code

Java tutorial

Introduction

Here is the source code for edu.cornell.mannlib.vitro.webapp.dao.jena.SparqlGraph.java

Source

/* $This file is distributed under the terms of the license in /doc/license.txt$ */

package edu.cornell.mannlib.vitro.webapp.dao.jena;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;

import com.hp.hpl.jena.graph.BulkUpdateHandler;
import com.hp.hpl.jena.graph.Capabilities;
import com.hp.hpl.jena.graph.Graph;
import com.hp.hpl.jena.graph.GraphEventManager;
import com.hp.hpl.jena.graph.GraphStatisticsHandler;
import com.hp.hpl.jena.graph.Node;
import com.hp.hpl.jena.graph.TransactionHandler;
import com.hp.hpl.jena.graph.Triple;
import com.hp.hpl.jena.graph.TripleMatch;
import com.hp.hpl.jena.graph.impl.GraphWithPerform;
import com.hp.hpl.jena.graph.impl.SimpleEventManager;
import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.shared.AddDeniedException;
import com.hp.hpl.jena.shared.DeleteDeniedException;
import com.hp.hpl.jena.shared.PrefixMapping;
import com.hp.hpl.jena.shared.impl.PrefixMappingImpl;
import com.hp.hpl.jena.sparql.resultset.ResultSetMem;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;
import com.hp.hpl.jena.util.iterator.SingletonIterator;
import com.hp.hpl.jena.util.iterator.WrappedIterator;

import edu.cornell.mannlib.vitro.webapp.utils.logging.ToString;

public class SparqlGraph implements GraphWithPerform {

    private String endpointURI;
    private String graphURI;
    private HttpClient httpClient;
    private static final Log log = LogFactory.getLog(SparqlGraph.class);

    private BulkUpdateHandler bulkUpdateHandler;
    private PrefixMapping prefixMapping = new PrefixMappingImpl();
    private GraphEventManager eventManager;

    /**
     * Returns a SparqlGraph for the union of named graphs in a remote repository 
     * @param endpointURI
     */
    public SparqlGraph(String endpointURI) {
        this(endpointURI, null);
    }

    /**
     * Returns a SparqlGraph for a particular named graph in a remote repository 
     * @param endpointURI
     * @param graphURI
     */
    public SparqlGraph(String endpointURI, String graphURI) {
        this.endpointURI = endpointURI;
        this.graphURI = graphURI;

        PoolingClientConnectionManager cm = new PoolingClientConnectionManager();
        cm.setDefaultMaxPerRoute(50);
        this.httpClient = new DefaultHttpClient(cm);
    }

    public String getEndpointURI() {
        return endpointURI;
    }

    public String getGraphURI() {
        return graphURI;
    }

    @Override
    public void add(Triple arg0) throws AddDeniedException {
        performAdd(arg0);
    }

    public void executeUpdate(String updateString) {
        try {
            HttpPost meth = new HttpPost(endpointURI);
            meth.addHeader("Content-Type", "application/x-www-form-urlencoded");
            meth.setEntity(new UrlEncodedFormEntity(Arrays.asList(new BasicNameValuePair("update", updateString))));
            HttpResponse response = httpClient.execute(meth);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode > 399) {
                log.error("response " + statusCode + " to update. \n");
                throw new RuntimeException("Unable to perform SPARQL UPDATE: \n" + updateString);
            }
        } catch (Exception e) {
            throw new RuntimeException("Unable to perform SPARQL UPDATE", e);
        }
    }

    @Override
    public void performAdd(Triple t) {

        //log.info("adding " + t);

        String updateString = "INSERT DATA { " + ((graphURI != null) ? "GRAPH <" + graphURI + "> { " : "")
                + sparqlNodeUpdate(t.getSubject(), "") + " " + sparqlNodeUpdate(t.getPredicate(), "") + " "
                + sparqlNodeUpdate(t.getObject(), "") + " } " + ((graphURI != null) ? " } " : "");

        if (graphURI != null) {
            log.info("=====> update to graph " + graphURI);
        }
        log.info(updateString);

        executeUpdate(updateString);

    }

    @Override
    public void performDelete(Triple t) {

        String updateString = "DELETE DATA { " + ((graphURI != null) ? "GRAPH <" + graphURI + "> { " : "")
                + sparqlNodeUpdate(t.getSubject(), "") + " " + sparqlNodeUpdate(t.getPredicate(), "") + " "
                + sparqlNodeUpdate(t.getObject(), "") + " } " + ((graphURI != null) ? " } " : "");

        //log.info(updateString);

        executeUpdate(updateString);
    }

    public void removeAll() {
        // now we flush out any remaining blank nodes
        String updateString = "DELETE { ?s ?p ?o } WHERE { \n"
                + ((getGraphURI() != null) ? ("GRAPH <" + getGraphURI() + "> { \n") : ("")) + "    ?s ?p ?o \n"
                + ((getGraphURI() != null) ? "} \n" : "") + "}";
        executeUpdate(updateString);
    }

    @Override
    public void close() {
        // can't close a remote endpoint
    }

    @Override
    public boolean contains(Triple arg0) {
        return contains(arg0.getSubject(), arg0.getPredicate(), arg0.getObject());
    }

    @Override
    public boolean contains(Node subject, Node predicate, Node object) {
        if ((subject != null && subject.isBlank()) || (predicate != null && predicate.isBlank())
                || (object != null && object.isBlank())) {
            return false;
        }
        StringBuffer containsQuery = new StringBuffer("ASK { \n");
        if (graphURI != null) {
            containsQuery.append("  GRAPH <" + graphURI + "> { ");
        }
        containsQuery.append(sparqlNode(subject, "?s")).append(" ").append(sparqlNode(predicate, "?p")).append(" ")
                .append(sparqlNode(object, "?o"));
        if (graphURI != null) {
            containsQuery.append(" } \n");
        }
        containsQuery.append("\n}");
        boolean result = execAsk(containsQuery.toString());
        return result;
    }

    @Override
    public void delete(Triple arg0) throws DeleteDeniedException {
        performDelete(arg0);
    }

    @Override
    public void clear() {
        removeAll();
    }

    @Override
    public void remove(Node subject, Node predicate, Node object) {
        for (Triple t : find(subject, predicate, object).toList()) {
            delete(t);
        }
    }

    @Override
    public boolean dependsOn(Graph arg0) {
        return false; // who knows?
    }

    @Override
    public ExtendedIterator<Triple> find(TripleMatch arg0) {
        //log.info("find(TripleMatch) " + arg0);
        Triple t = arg0.asTriple();
        return find(t.getSubject(), t.getPredicate(), t.getObject());
    }

    public static String sparqlNode(Node node, String varName) {
        if (node == null || node.isVariable()) {
            return varName;
        } else if (node.isBlank()) {
            return "<fake:blank>"; // or throw exception?
        } else if (node.isURI()) {
            StringBuffer uriBuff = new StringBuffer();
            return uriBuff.append("<").append(node.getURI()).append(">").toString();
        } else if (node.isLiteral()) {
            StringBuffer literalBuff = new StringBuffer();
            literalBuff.append("\"");
            pyString(literalBuff, node.getLiteralLexicalForm());
            literalBuff.append("\"");
            if (node.getLiteralDatatypeURI() != null) {
                literalBuff.append("^^<").append(node.getLiteralDatatypeURI()).append(">");
            } else if (node.getLiteralLanguage() != null && node.getLiteralLanguage() != "") {
                literalBuff.append("@").append(node.getLiteralLanguage());
            }
            return literalBuff.toString();
        } else {
            return varName;
        }
    }

    public static String sparqlNodeUpdate(Node node, String varName) {
        if (node.isBlank()) {
            return "_:" + node.getBlankNodeLabel().replaceAll("\\W", "");
        } else {
            return sparqlNode(node, varName);
        }
    }

    public static String sparqlNodeDelete(Node node, String varName) {
        if (node.isBlank()) {
            return "?" + node.getBlankNodeLabel().replaceAll("\\W", "");
        } else {
            return sparqlNode(node, varName);
        }
    }

    @Override
    public ExtendedIterator<Triple> find(Node subject, Node predicate, Node object) {
        if (!isVar(subject) && !isVar(predicate) && !isVar(object)) {
            if (contains(subject, predicate, object)) {
                return new SingletonIterator<Triple>(new Triple(subject, predicate, object));
            } else {
                return WrappedIterator.create(Collections.<Triple>emptyIterator());
            }
        }
        StringBuffer findQuery = new StringBuffer("SELECT * WHERE { \n");
        if (graphURI != null) {
            findQuery.append("  GRAPH <" + graphURI + "> { ");
        }
        findQuery.append(sparqlNode(subject, "?s")).append(" ").append(sparqlNode(predicate, "?p")).append(" ")
                .append(sparqlNode(object, "?o"));
        if (graphURI != null) {
            findQuery.append("  } ");
        }
        findQuery.append("\n}");

        String queryString = findQuery.toString();
        //log.info(queryString);

        //        //TODO remove me
        //        if (queryString.contains("individual/AI") && queryString.contains("label")) {
        //            throw new RuntimeException("break!");
        //        }

        ResultSet rs = execSelect(queryString);
        //rs = execSelect(findQuery.toString());
        //rs = execSelect(findQuery.toString());

        List<Triple> triplist = new ArrayList<Triple>();
        while (rs.hasNext()) {
            QuerySolution soln = rs.nextSolution();
            Triple t = new Triple(isVar(subject) ? soln.get("?s").asNode() : subject,
                    isVar(predicate) ? soln.get("?p").asNode() : predicate,
                    isVar(object) ? soln.get("?o").asNode() : object);
            //log.info(t);
            triplist.add(t);
        }
        //log.info(triplist.size() + " results");
        return WrappedIterator.create(triplist.iterator());
    }

    private boolean isVar(Node node) {
        return (node == null || node.isVariable() || node == Node.ANY);
    }

    @Override
    @Deprecated
    public BulkUpdateHandler getBulkUpdateHandler() {
        if (this.bulkUpdateHandler == null) {
            this.bulkUpdateHandler = new SparqlGraphBulkUpdater(this);
        }
        return this.bulkUpdateHandler;
    }

    @Override
    public Capabilities getCapabilities() {
        return capabilities;
    }

    @Override
    public GraphEventManager getEventManager() {
        if (eventManager == null) {
            eventManager = new SimpleEventManager(this);
        }
        return eventManager;
    }

    @Override
    public PrefixMapping getPrefixMapping() {
        return prefixMapping;
    }

    @Override
    public GraphStatisticsHandler getStatisticsHandler() {
        return null;
    }

    @Override
    public TransactionHandler getTransactionHandler() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public boolean isClosed() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isEmpty() {
        return !contains(null, null, null);
    }

    @Override
    public boolean isIsomorphicWith(Graph arg0) {
        log.info("Hey dummy!");
        throw new UnsupportedOperationException("isIsomorphicWith() not supported " + "by SPARQL graphs");
    }

    @Override
    public int size() {
        int size = find(null, null, null).toList().size();
        return size;
    }

    private final static Capabilities capabilities = new Capabilities() {

        @Override
        public boolean addAllowed() {
            return false;
        }

        @Override
        public boolean addAllowed(boolean everyTriple) {
            return false;
        }

        @Override
        public boolean canBeEmpty() {
            return true;
        }

        @Override
        public boolean deleteAllowed() {
            return false;
        }

        @Override
        public boolean deleteAllowed(boolean everyTriple) {
            return false;
        }

        @Override
        public boolean findContractSafe() {
            return true;
        }

        @Override
        public boolean handlesLiteralTyping() {
            return true;
        }

        @Override
        public boolean iteratorRemoveAllowed() {
            return false;
        }

        @Override
        public boolean sizeAccurate() {
            return true;
        }
    };

    private boolean execAsk(String queryStr) {
        Query askQuery = QueryFactory.create(queryStr);
        QueryExecution qe = QueryExecutionFactory.sparqlService(endpointURI, askQuery);
        try {
            return qe.execAsk();
        } finally {
            qe.close();
        }
    }

    private ResultSet execSelect(String queryStr) {

        //        long startTime1 = System.currentTimeMillis();
        //        try {
        //            
        //            RepositoryConnection conn = getConnection();
        //            try {
        //                GraphQuery q = conn.prepareGraphQuery(QueryLanguage.SPARQL, queryStr);
        //                q.evaluate();
        //            } catch (MalformedQueryException e) {
        //                throw new RuntimeException(e);
        //            } finally {
        //                conn.close();
        //            }
        //        } catch (Exception re) {
        //            //log.info(re,re);
        //        }

        //        log.info((System.currentTimeMillis() - startTime1) + " to execute via sesame");

        Query askQuery = QueryFactory.create(queryStr);
        QueryExecution qe = QueryExecutionFactory.sparqlService(endpointURI, askQuery);
        try {
            return new ResultSetMem(qe.execSelect());
        } finally {
            qe.close();
        }
    }

    /*
     * 
     * see http://www.python.org/doc/2.5.2/ref/strings.html
     * or see jena's n3 grammar jena/src/com/hp/hpl/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;
            }

            // 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;
            }

            // Output as is (subject to UTF-8 encoding on output that is)
            sbuff.append(c);

            //            // Unicode escapes
            //            // c < 32, c >= 127, not whitespace or other specials
            //            String hexstr = Integer.toHexString(c).toUpperCase();
            //            int pad = 4 - hexstr.length();
            //            sbuff.append("\\u");
            //            for (; pad > 0; pad--)
            //                sbuff.append("0");
            //            sbuff.append(hexstr);
        }
    }

    @Override
    public String toString() {
        return "SparqlGraph[" + ToString.hashHex(this) + ", endpoint=" + endpointURI + ", name="
                + ToString.modelName(graphURI) + "]";
    }

}