com.clarkparsia.fourstore.sesame.FourStoreRepositoryConnection.java Source code

Java tutorial

Introduction

Here is the source code for com.clarkparsia.fourstore.sesame.FourStoreRepositoryConnection.java

Source

/*
 * Copyright (c) 2009-2010 Clark & Parsia, LLC. <http://www.clarkparsia.com>
 *
 * 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.
 */

package com.clarkparsia.fourstore.sesame;

import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.RepositoryConnection;

import org.openrdf.repository.sail.SailRepositoryConnection;
import org.openrdf.repository.sail.SailTupleQuery;
import org.openrdf.repository.sail.SailGraphQuery;

import org.openrdf.sail.SailException;
import org.openrdf.model.Graph;
import org.openrdf.model.Resource;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.model.Statement;
import org.openrdf.model.impl.GraphImpl;
import org.openrdf.model.impl.StatementImpl;
import org.openrdf.rio.RDFFormat;
import org.openrdf.rio.RDFParseException;
import org.openrdf.rio.RDFHandler;
import org.openrdf.rio.RDFHandlerException;

import org.openrdf.query.QueryLanguage;
import org.openrdf.query.MalformedQueryException;
import org.openrdf.query.GraphQueryResult;
import org.openrdf.query.QueryEvaluationException;
import org.openrdf.query.TupleQueryResultHandler;
import org.openrdf.query.TupleQueryResult;
import org.openrdf.query.impl.GraphQueryResultImpl;
import org.openrdf.query.impl.TupleQueryResultBuilder;
import org.openrdf.query.parser.sparql.SPARQLParserFactory;
import org.openrdf.query.parser.ParsedQuery;
import org.openrdf.query.parser.QueryParserFactory;
import org.openrdf.query.parser.QueryParserUtil;
import org.openrdf.query.parser.ParsedGraphQuery;
import org.openrdf.query.parser.ParsedTupleQuery;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.io.IOException;
import java.io.Reader;
import java.io.File;

import java.io.FileInputStream;
import java.io.ByteArrayInputStream;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;

import info.aduna.iteration.Iteration;

import com.clarkparsia.openrdf.util.GraphBuildingRDFHandler;
import com.clarkparsia.openrdf.query.sparql.SPARQLQueryRenderer;
import com.google.common.base.Charsets;
import com.google.common.io.CharStreams;
import com.google.common.collect.Sets;

/**
 * <p>Extends the Sesame SailRepositoryConnection class to provide a connection interface to a remote 4store instance.
 * Overrides the default behavior for adds, removes and queries so they operate directly on the 4store instance instead
 * of going through the Sail/Repository API which just unnecessarily slows down the performance of the repository.</p>
 *
 * @author Michael Grove
 */
public class FourStoreRepositoryConnection extends SailRepositoryConnection {
    /**
     * The logger
     */
    private static final Logger LOGGER = LoggerFactory.getLogger("4store");

    /**
     * Create a new FourStoreRepositoryConnection
     * @param theFourStoreSail the instance of four store to operate on
     * @throws SailException thrown if a connection cannot be established.
     */
    protected FourStoreRepositoryConnection(final FourStoreSailRepository theFourStoreSail) throws SailException {
        super(theFourStoreSail, theFourStoreSail.getFourStoreSail().getConnection());
    }

    /**
     * Return the underlying SailConnection casted as a {@link FourStoreSailConnection}.
     * @return the SailConnection as a FourStoreSailConnection
     */
    private FourStoreSailConnection getFourStoreSailConnection() {
        // this is a safe cast as the underlying sail can only ever be a FourStoreSail
        return (FourStoreSailConnection) getSailConnection();
    }

    /**
     * @inheritDoc
     */
    @Override
    public SailTupleQuery prepareTupleQuery(final QueryLanguage theQueryLanguage, final String theQuery)
            throws MalformedQueryException {
        return prepareTupleQuery(theQueryLanguage, theQuery, "http://4store.clarkparsia.com");
    }

    /**
     * @inheritDoc
     */
    @Override
    public SailTupleQuery prepareTupleQuery(final QueryLanguage theQueryLanguage, final String theQuery,
            final String theBaseURI) throws MalformedQueryException {
        ParsedTupleQuery aQuery = QueryParserUtil.parseTupleQuery(theQueryLanguage, theQuery, theBaseURI);

        return new FourStoreSailTupleQuery(aQuery, this);
    }

    /**
     * @inheritDoc
     */
    @Override
    public SailGraphQuery prepareGraphQuery(final QueryLanguage theQueryLanguage, final String theQuery)
            throws MalformedQueryException {
        return prepareGraphQuery(theQueryLanguage, theQuery, "http://4store.clarkparsia.com/");
    }

    /**
     * @inheritDoc
     */
    @Override
    public SailGraphQuery prepareGraphQuery(final QueryLanguage theQueryLanguage, final String theQuery,
            final String theBaseURI) throws MalformedQueryException {
        ParsedGraphQuery aQuery = QueryParserUtil.parseGraphQuery(theQueryLanguage, theQuery, theBaseURI);

        return new FourStoreSailGraphQuery(aQuery, this);
    }

    /**
     * @inheritDoc
     */
    @Override
    public void add(final InputStream theInputStream, final String theBaseURI, final RDFFormat theRDFFormat,
            final Resource... theContexts) throws IOException, RDFParseException, RepositoryException {
        if (theBaseURI != null && theBaseURI.length() > 0) {
            LOGGER.warn("Ignoring specified base URI");
        }

        try {
            getFourStoreSailConnection().add(theInputStream, theRDFFormat, theContexts);
        } catch (SailException e) {
            throw new RepositoryException(e);
        }
    }

    /**
     * @inheritDoc
     */
    @Override
    public void add(final Reader theReader, final String theBaseURI, final RDFFormat theRDFFormat,
            final Resource... theContexts) throws IOException, RDFParseException, RepositoryException {
        // this is not terribly efficient, reading in the contents of the reader like this.  but our 4store api doesn't
        // expose something to handle Reader's since you cannot pass a Reader to an HTTPConnection.
        // could always do something like this:  http://www.koders.com/java/fid0A51E45C950B2B8BD9365C19F2626DE35EC09090.aspx

        add(new ByteArrayInputStream(CharStreams.toString(theReader).getBytes(Charsets.UTF_8)), theBaseURI,
                theRDFFormat, theContexts);
    }

    /**
     * @inheritDoc
     */
    @Override
    public void add(final URL theURL, final String theBaseURI, final RDFFormat theRDFFormat,
            final Resource... theContexts) throws IOException, RDFParseException, RepositoryException {
        add(theURL.openStream(), theBaseURI, theRDFFormat, theContexts);
    }

    /**
     * @inheritDoc
     */
    @Override
    public void add(final File theFile, final String theBaseURI, final RDFFormat theRDFFormat,
            final Resource... theContexts) throws IOException, RDFParseException, RepositoryException {
        add(new FileInputStream(theFile), theBaseURI, theRDFFormat, theContexts);
    }

    /**
     * @inheritDoc
     */
    @Override
    public void add(final Resource theResource, final URI theURI, final Value theValue,
            final Resource... theContexts) throws RepositoryException {
        try {
            getSailConnection().addStatement(theResource, theURI, theValue, theContexts);
        } catch (SailException e) {
            throw new RepositoryException(e);
        }
    }

    /**
     * @inheritDoc
     */
    @Override
    public void add(final Statement theStatement, final Resource... theContexts) throws RepositoryException {
        try {
            getSailConnection().addStatement(theStatement.getSubject(), theStatement.getPredicate(),
                    theStatement.getObject(), theContexts);
        } catch (SailException e) {
            throw new RepositoryException(e);
        }
    }

    /**
     * @inheritDoc
     */
    @Override
    public void add(final Iterable<? extends Statement> theIterable, final Resource... theContexts)
            throws RepositoryException {
        Graph aGraph = new GraphImpl();
        aGraph.addAll(Sets.newHashSet(theIterable));

        try {
            getFourStoreSailConnection().add(aGraph, theContexts);
        } catch (SailException e) {
            throw new RepositoryException(e);
        }
    }

    /**
     * @inheritDoc
     */
    @Override
    public <E extends Exception> void add(final Iteration<? extends Statement, E> theIteration,
            final Resource... theContexts) throws RepositoryException, E {
        Graph aGraph = new GraphImpl();

        while (theIteration.hasNext()) {
            aGraph.add(theIteration.next());
        }

        try {
            getFourStoreSailConnection().add(aGraph, theContexts);
        } catch (SailException e) {
            throw new RepositoryException(e);
        }
    }

    /**
     * @inheritDoc
     */
    @Override
    public void remove(final Resource theSubject, final URI thePredicate, final Value theObject,
            final Resource... theContexts) throws RepositoryException {
        remove(new StatementImpl(theSubject, thePredicate, theObject), theContexts);
    }

    /**
     * @inheritDoc
     */
    @Override
    public void remove(final Statement theStatement, final Resource... theContexts) throws RepositoryException {
        remove(Collections.singleton(theStatement), theContexts);
    }

    /**
     * @inheritDoc
     */
    @Override
    public void remove(final Iterable<? extends Statement> theIterable, final Resource... theContexts)
            throws RepositoryException {
        Graph aGraph = new GraphImpl();

        aGraph.addAll(Sets.newHashSet(theIterable));

        try {
            getFourStoreSailConnection().remove(aGraph, theContexts);
        } catch (SailException e) {
            throw new RepositoryException(e);
        }
    }

    /**
     * @inheritDoc
     */
    @Override
    public <E extends Exception> void remove(final Iteration<? extends Statement, E> theIteration,
            final Resource... theContexts) throws RepositoryException, E {
        Graph aGraph = new GraphImpl();

        while (theIteration.hasNext()) {
            aGraph.add(theIteration.next());
        }

        try {
            getFourStoreSailConnection().remove(aGraph, theContexts);
        } catch (SailException e) {
            throw new RepositoryException(e);
        }
    }

    /**
     * Extends the Sesame SailGraphQuery to circumvent their naive query implementation and operate directly on the
     * underlying four store sail so the queries go straight to 4store instead of through the Sesame layer.
     */
    private static class FourStoreSailGraphQuery extends SailGraphQuery {

        /**
         * Create a new FourStoreSailGraphQuery
         * @param theQuery the query that will be dispatched
         * @param theFourStoreRepositoryConnection the connection to be used to answer the query
         */
        public FourStoreSailGraphQuery(final ParsedGraphQuery theQuery,
                final FourStoreRepositoryConnection theFourStoreRepositoryConnection) {
            super(theQuery, theFourStoreRepositoryConnection);
        }

        /**
         * @inheritDoc
         */
        @Override
        public GraphQueryResult evaluate() throws QueryEvaluationException {
            try {
                GraphBuildingRDFHandler aHandler = new GraphBuildingRDFHandler();

                evaluate(aHandler);

                return new GraphQueryResultImpl(new HashMap<String, String>(), aHandler.getGraph());
            } catch (RDFHandlerException e) {
                throw new QueryEvaluationException(e);
            }
        }

        /**
         * @inheritDoc
         */
        @Override
        public void evaluate(RDFHandler theHandler) throws QueryEvaluationException, RDFHandlerException {
            try {
                Graph aGraph = ((FourStoreRepositoryConnection) this.getConnection()).getFourStoreSailConnection()
                        .graphQuery(new SPARQLQueryRenderer().render(getParsedQuery()));

                theHandler.startRDF();
                for (Statement aStmt : aGraph) {
                    theHandler.handleStatement(aStmt);
                }
                theHandler.endRDF();
            } catch (Exception e) {
                throw new QueryEvaluationException(e);
            }
        }
    }

    /**
     * Etends the Sesame SailTupleQuery to circumvent their naive query implementation to dispatch the query directly
     * to 4store via the underlying fourstore sail.
     */
    private static class FourStoreSailTupleQuery extends SailTupleQuery {

        /**
         * Create a new FourStoreSailTupleQuery
         * @param theParsedTupleQuery the query that will be dispatched
         * @param theFourStoreRepositoryConnection the connection to be used to answer the query
         */
        protected FourStoreSailTupleQuery(final ParsedTupleQuery theParsedTupleQuery,
                final FourStoreRepositoryConnection theFourStoreRepositoryConnection) {
            super(theParsedTupleQuery, theFourStoreRepositoryConnection);
        }

        /**
         * @inheritDoc
         */
        @Override
        public TupleQueryResult evaluate() throws QueryEvaluationException {
            TupleQueryResultBuilder aBuilder = new TupleQueryResultBuilder();

            evaluate(aBuilder);

            return aBuilder.getQueryResult();
        }

        /**
         * @inheritDoc
         */
        @Override
        public void evaluate(TupleQueryResultHandler theHandler) throws QueryEvaluationException {
            try {
                TupleQueryResult aResult = ((FourStoreRepositoryConnection) this.getConnection())
                        .getFourStoreSailConnection().query(new SPARQLQueryRenderer().render(getParsedQuery()));

                theHandler.startQueryResult(aResult.getBindingNames());
                while (aResult.hasNext()) {
                    theHandler.handleSolution(aResult.next());
                }
                theHandler.endQueryResult();
            } catch (Exception e) {
                throw new QueryEvaluationException(e);
            }
        }
    }
}