Package org.apache.marmotta.kiwi.versioning.sail

Source Code of org.apache.marmotta.kiwi.versioning.sail.KiWiSnapshotConnection$KiWiTripleSource

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.marmotta.kiwi.versioning.sail;

import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import info.aduna.iteration.CloseableIteration;
import info.aduna.iteration.DelayedIteration;
import info.aduna.iteration.ExceptionConvertingIteration;
import info.aduna.iteration.Iteration;
import info.aduna.iteration.UnionIteration;
import org.apache.marmotta.kiwi.model.rdf.KiWiNamespace;
import org.apache.marmotta.kiwi.model.rdf.KiWiNode;
import org.apache.marmotta.kiwi.model.rdf.KiWiResource;
import org.apache.marmotta.kiwi.model.rdf.KiWiUriResource;
import org.apache.marmotta.kiwi.sail.KiWiValueFactory;
import org.apache.marmotta.kiwi.versioning.persistence.KiWiVersioningConnection;
import org.openrdf.model.Namespace;
import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.model.ValueFactory;
import org.openrdf.query.BindingSet;
import org.openrdf.query.Dataset;
import org.openrdf.query.QueryEvaluationException;
import org.openrdf.query.QueryInterruptedException;
import org.openrdf.query.algebra.QueryRoot;
import org.openrdf.query.algebra.StatementPattern;
import org.openrdf.query.algebra.TupleExpr;
import org.openrdf.query.algebra.Var;
import org.openrdf.query.algebra.evaluation.EvaluationStrategy;
import org.openrdf.query.algebra.evaluation.TripleSource;
import org.openrdf.query.algebra.evaluation.impl.*;
import org.openrdf.repository.RepositoryException;
import org.openrdf.sail.SailConnection;
import org.openrdf.sail.SailException;
import org.openrdf.sail.SailReadOnlyException;
import org.openrdf.sail.UnknownSailTransactionStateException;
import org.openrdf.sail.UpdateContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.channels.ClosedByInterruptException;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

/**
* Add file description here!
* <p/>
* Author: Sebastian Schaffert
*/
public class KiWiSnapshotConnection implements SailConnection {


    private KiWiVersioningConnection databaseConnection;

    private Date snapshotDate;

    private String defaultContext;

    private KiWiValueFactory valueFactory;

    private KiWiVersioningSail parent;

    public KiWiSnapshotConnection(KiWiVersioningSail sailBase, Date snapshotDate) throws SailException {
        this.snapshotDate = snapshotDate;
        try {
            this.databaseConnection = sailBase.getPersistence().getConnection();
            this.defaultContext     = sailBase.getBaseStore().getDefaultContext();
            this.valueFactory       = new KiWiValueFactory(sailBase.getBaseStore(),defaultContext);
            this.parent             = sailBase;
        } catch (SQLException e) {
            throw new SailException("error establishing database connection",e);
        }
    }

    /**
     * Return the date for which this snapshot is valid.
     * @return
     */
    public Date getSnapshotDate() {
        return snapshotDate;
    }

    @Override
    public void addStatement(Resource subj, URI pred, Value obj, Resource... contexts) throws SailException {
        throw new SailReadOnlyException("snapshot sails are read-only");
    }

    @Override
    public void close() throws SailException {
        try {
            databaseConnection.close();

            parent.closeSnapshotConnection(this);
        } catch (SQLException e) {
            throw new SailException("database error while closing connection",e);
        }
    }

    @Override
    public CloseableIteration<? extends BindingSet, QueryEvaluationException> evaluate(TupleExpr tupleExpr, Dataset dataset, BindingSet bindings, boolean includeInferred) throws SailException {
        // Clone the tuple expression to allow for more aggressive optimizations
        tupleExpr = tupleExpr.clone();

        if (!(tupleExpr instanceof QueryRoot)) {
            // Add a dummy root node to the tuple expressions to allow the
            // optimizers to modify the actual root node
            tupleExpr = new QueryRoot(tupleExpr);
        }

        try {
            KiWiTripleSource tripleSource = new KiWiTripleSource(this,includeInferred);
            EvaluationStrategy strategy = new EvaluationStrategyImpl(tripleSource, dataset);

            new BindingAssigner().optimize(tupleExpr, dataset, bindings);
            new ConstantOptimizer(strategy).optimize(tupleExpr, dataset, bindings);
            new CompareOptimizer().optimize(tupleExpr, dataset, bindings);
            new ConjunctiveConstraintSplitter().optimize(tupleExpr, dataset, bindings);
            new DisjunctiveConstraintOptimizer().optimize(tupleExpr, dataset, bindings);
            new SameTermFilterOptimizer().optimize(tupleExpr, dataset, bindings);
            new QueryModelNormalizer().optimize(tupleExpr, dataset, bindings);
            new QueryJoinOptimizer(new KiWiEvaluationStatistics()).optimize(tupleExpr, dataset, bindings);
            new IterativeEvaluationOptimizer().optimize(tupleExpr, dataset, bindings);
            new FilterOptimizer().optimize(tupleExpr, dataset, bindings);
            new OrderLimitOptimizer().optimize(tupleExpr, dataset, bindings);

            return strategy.evaluate(tupleExpr, bindings);

        } catch (QueryEvaluationException e) {
            throw new SailException(e);
        }
    }

    @Override
    public CloseableIteration<? extends Resource, SailException> getContextIDs() throws SailException {
        try {
            return new ExceptionConvertingIteration<Resource, SailException>(databaseConnection.listContexts()) {
                @Override
                protected SailException convert(Exception e) {
                    return new SailException("database error while iterating over result set",e);
                }
            };
        } catch (SQLException e) {
            throw new SailException("database error while listing contexts",e);
        }
    }

    @Override
    public CloseableIteration<? extends Statement, SailException> getStatements(Resource subj, URI pred, Value obj, final boolean includeInferred, Resource... contexts) throws SailException {
        final KiWiResource rsubj    = valueFactory.convert(subj);
        final KiWiUriResource rpred = valueFactory.convert(pred);
        final KiWiNode robj         = valueFactory.convert(obj);

        Set<KiWiResource> contextSet = new HashSet<KiWiResource>();
        contextSet.addAll(Lists.transform(Arrays.asList(contexts), new Function<Resource, KiWiResource>() {
            @Override
            public KiWiResource apply(Resource input) {
                return valueFactory.convert(input);
            }
        }));

        Set<DelayedIteration<Statement,RepositoryException>> iterations = new HashSet<DelayedIteration<Statement, RepositoryException>>();
        if(contextSet.size() > 0) {
            for(final KiWiResource context : contextSet) {
                iterations.add(new DelayedIteration<Statement, RepositoryException>() {
                    @Override
                    protected Iteration<? extends Statement, ? extends RepositoryException> createIteration() throws RepositoryException {
                        try {
                            return databaseConnection.listTriplesSnapshot(rsubj, rpred, robj, context, includeInferred, snapshotDate);
                        } catch (SQLException e) {
                            throw new RepositoryException("database error while listing triples",e);
                        }
                    }
                });
            }
        } else {
            iterations.add(new DelayedIteration<Statement, RepositoryException>() {
                @Override
                protected Iteration<? extends Statement, ? extends RepositoryException> createIteration() throws RepositoryException {
                    try {
                        return databaseConnection.listTriplesSnapshot(rsubj, rpred, robj, null, includeInferred, snapshotDate);
                    } catch (SQLException e) {
                        throw new RepositoryException("database error while listing triples",e);
                    }
                }
            });
        }


        return new UnionIteration<Statement, SailException>(
                Iterables.transform(iterations, new Function<DelayedIteration<Statement, RepositoryException>, Iteration<? extends Statement, SailException>>() {
                    @Override
                    public Iteration<? extends Statement, SailException> apply(DelayedIteration<Statement, RepositoryException> input) {
                        return new ExceptionConvertingIteration<Statement, SailException>(input) {
                            /**
                             * Converts an exception from the underlying iteration to an exception of
                             * type <tt>X</tt>.
                             */
                            @Override
                            protected SailException convert(Exception e) {
                                return new SailException("database error while iterating over result set", e);
                            }
                        };
                    }
                })
        );
    }

    @Override
    public long size(Resource... contexts) throws SailException {
        try {
            if(contexts.length == 0) {
                return databaseConnection.getSnapshotSize(snapshotDate);
            } else {
                long sum = 0;
                for(Resource context : contexts) {
                    sum += databaseConnection.getSnapshotSize(valueFactory.convert(context),snapshotDate);
                }
                return sum;
            }
        } catch(SQLException ex) {
            throw new SailException("database error while listing triples",ex);
        }
    }

    @Override
    public void begin() throws SailException {
    }

    @Override
    public void commit() throws SailException {
        try {
            databaseConnection.commit();
        } catch (SQLException e) {
            throw new SailException("database error while committing transaction",e);
        }
    }

    @Override
    public void rollback() throws SailException {
        try {
            databaseConnection.rollback();
        } catch (SQLException e) {
            throw new SailException("database error while committing transaction",e);
        }
    }

    @Override
    public void removeStatements(Resource subj, URI pred, Value obj, Resource... contexts) throws SailException {
        throw new SailReadOnlyException("snapshot sails are read-only");
    }

    @Override
    public void clear(Resource... contexts) throws SailException {
        throw new SailReadOnlyException("snapshot sails are read-only");
    }

    @Override
    public CloseableIteration<? extends Namespace, SailException> getNamespaces() throws SailException {
        try {
            return new ExceptionConvertingIteration<Namespace, SailException>(databaseConnection.listNamespaces()) {
                /**
                 * Converts an exception from the underlying iteration to an exception of
                 * type <tt>X</tt>.
                 */
                @Override
                protected SailException convert(Exception e) {
                    return new SailException("database error while iterating over namespaces",e);
                }
            };
        } catch (SQLException e) {
            throw new SailException("database error while querying namespaces",e);
        }
    }

    @Override
    public String getNamespace(String prefix) throws SailException {
        try {
            KiWiNamespace result = databaseConnection.loadNamespaceByPrefix(prefix);
            if(result != null) {
                return result.getUri();
            } else {
                return null;
            }
        } catch (SQLException e) {
            throw new SailException("database error while querying namespaces",e);
        }
    }

    @Override
    public void setNamespace(String prefix, String name) throws SailException {
        throw new SailReadOnlyException("snapshot sails are read-only");
    }

    @Override
    public void removeNamespace(String prefix) throws SailException {
        throw new SailReadOnlyException("snapshot sails are read-only");
    }

    @Override
    public void clearNamespaces() throws SailException {
        throw new SailReadOnlyException("snapshot sails are read-only");
    }


    /**
     * Adds a statement to the store. Called when adding statements through a
     * {@link org.openrdf.query.algebra.UpdateExpr} operation.
     *
     * @param op       operation properties of the {@link org.openrdf.query.algebra.UpdateExpr} operation producing
     *                 these statements.
     * @param subj     The subject of the statement to add.
     * @param pred     The predicate of the statement to add.
     * @param obj      The object of the statement to add.
     * @param contexts The context(s) to add the statement to. Note that this parameter is
     *                 a vararg and as such is optional. If no contexts are specified, a
     *                 context-less statement will be added.
     * @throws org.openrdf.sail.SailException If the statement could not be added, for example because no
     *                                        transaction is active.
     * @throws IllegalStateException          If the connection has been closed.
     */
    @Override
    public void addStatement(UpdateContext op, Resource subj, URI pred, Value obj, Resource... contexts) throws SailException {
        throw new SailReadOnlyException("snapshot sails are read-only");
    }

    /**
     * Checks for an error state in the active transaction that would force the
     * transaction to be rolled back. This is an optional call; calling or not
     * calling this method should have no effect on the outcome of
     * {@link #commit()} or {@link #rollback()}. A call to this method must be
     * followed by (in the same thread) with a call to {@link #prepare()} ,
     * {@link #commit()}, {@link #rollback()}, or {@link #close()}. This method
     * may be called multiple times within the same transaction by the same
     * thread. If this method returns normally, the caller can reasonably expect
     * that a subsequent call to {@link #commit()} will also return normally. If
     * this method returns with an exception the caller should treat the
     * exception as if it came from a call to {@link #commit()}.
     *
     * @throws org.openrdf.sail.UnknownSailTransactionStateException
     *                                        If the transaction state can not be determined (this can happen
     *                                        for instance when communication between client and server fails or
     *                                        times-out). It does not indicate a problem with the integrity of
     *                                        the store.
     * @throws org.openrdf.sail.SailException If there is an active transaction and it cannot be committed.
     * @throws IllegalStateException          If the connection has been closed or prepare was already called by
     *                                        another thread.
     * @since 2.7.0
     */
    @Override
    public void prepare() throws SailException {
        throw new SailReadOnlyException("snapshot sails are read-only");
    }

    /**
     * Signals the start of an update operation. The given <code>op</code> maybe
     * passed to subsequent
     * {@link #addStatement(org.openrdf.sail.UpdateContext, org.openrdf.model.Resource, org.openrdf.model.URI, org.openrdf.model.Value, org.openrdf.model.Resource...)} or
     * {@link #removeStatement(org.openrdf.sail.UpdateContext, org.openrdf.model.Resource, org.openrdf.model.URI, org.openrdf.model.Value, org.openrdf.model.Resource...)}
     * calls before {@link #endUpdate(org.openrdf.sail.UpdateContext)} is called.
     *
     * @throws org.openrdf.sail.SailException
     */
    @Override
    public void startUpdate(UpdateContext op) throws SailException {
        throw new SailReadOnlyException("snapshot sails are read-only");
    }

    /**
     * Removes all statements matching the specified subject, predicate and
     * object from the repository. All three parameters may be null to indicate
     * wildcards. Called when removing statements through a {@link org.openrdf.query.algebra.UpdateExpr}
     * operation.
     *
     * @param op       operation properties of the {@link org.openrdf.query.algebra.UpdateExpr} operation removing these
     *                 statements.
     * @param subj     The subject of the statement that should be removed.
     * @param pred     The predicate of the statement that should be removed.
     * @param obj      The object of the statement that should be removed.
     * @param contexts The context(s) from which to remove the statement. Note that this
     *                 parameter is a vararg and as such is optional. If no contexts are
     *                 specified the method operates on the entire repository. A
     *                 <tt>null</tt> value can be used to match context-less statements.
     * @throws org.openrdf.sail.SailException If the statement could not be removed, for example because no
     *                                        transaction is active.
     * @throws IllegalStateException          If the connection has been closed.
     */
    @Override
    public void removeStatement(UpdateContext op, Resource subj, URI pred, Value obj, Resource... contexts) throws SailException {
        throw new SailReadOnlyException("snapshot sails are read-only");
    }

    /**
     * Indicates that the given <code>op</code> will not be used in any call
     * again. Implementations should use this to flush of any temporary operation
     * states that may have occurred.
     *
     * @param op
     * @throws org.openrdf.sail.SailException
     */
    @Override
    public void endUpdate(UpdateContext op) throws SailException {
        throw new SailReadOnlyException("snapshot sails are read-only");
    }

    @Override
    public boolean isOpen() throws SailException {
        try {
            return !databaseConnection.isClosed();
        } catch (SQLException e) {
            throw new SailException("database error while accessing connection", e);
        }
    }

    @Override
    public boolean isActive() throws UnknownSailTransactionStateException {
        try {
            return isOpen();
        } catch (SailException e) {
            throw new UnknownSailTransactionStateException("unknown sail transaction state, error accessing database");
        }
    }

    private static class KiWiTripleSource implements TripleSource {

        private boolean inferred;
        private KiWiSnapshotConnection connection;

        private KiWiTripleSource(KiWiSnapshotConnection connection, boolean inferred) {
            this.inferred   = inferred;
            this.connection = connection;
        }

        /**
         * Gets all statements that have a specific subject, predicate and/or object.
         * All three parameters may be null to indicate wildcards. Optionally a (set
         * of) context(s) may be specified in which case the result will be
         * restricted to statements matching one or more of the specified contexts.
         *
         * @param subj     A Resource specifying the subject, or <tt>null</tt> for a
         *                 wildcard.
         * @param pred     A URI specifying the predicate, or <tt>null</tt> for a wildcard.
         * @param obj      A Value specifying the object, or <tt>null</tt> for a wildcard.
         * @param contexts The context(s) to get the statements from. Note that this parameter
         *                 is a vararg and as such is optional. If no contexts are supplied
         *                 the method operates on the entire repository.
         * @return An iterator over the relevant statements.
         * @throws org.openrdf.query.QueryEvaluationException
         *          If the triple source failed to get the statements.
         */
        @Override
        public CloseableIteration<? extends Statement, QueryEvaluationException> getStatements(Resource subj, URI pred, Value obj, Resource... contexts) throws QueryEvaluationException {
            try {
                return new ExceptionConvertingIteration<Statement, QueryEvaluationException>(
                        connection.getStatements(subj, pred, obj, inferred, contexts)
                ) {
                    @Override
                    protected QueryEvaluationException convert(Exception e) {
                        if (e instanceof ClosedByInterruptException) {
                            return new QueryInterruptedException(e);
                        }
                        else if (e instanceof IOException) {
                            return new QueryEvaluationException(e);
                        }
                        else if (e instanceof RuntimeException) {
                            throw (RuntimeException)e;
                        }
                        else if (e == null) {
                            throw new IllegalArgumentException("e must not be null");
                        }
                        else {
                            throw new IllegalArgumentException("Unexpected exception type: " + e.getClass());
                        }
                    }
                };
            } catch (SailException ex) {
                throw new QueryEvaluationException(ex);
            }
        }

        /**
         * Gets a ValueFactory object that can be used to create URI-, blank node-
         * and literal objects.
         *
         * @return a ValueFactory object for this TripleSource.
         */
        @Override
        public ValueFactory getValueFactory() {
            return connection.valueFactory;
        }
    }


    private static class KiWiEvaluationStatistics extends EvaluationStatistics {

        private final Logger log = LoggerFactory.getLogger(this.getClass());

        public KiWiEvaluationStatistics() {
        }

        @Override
        protected CardinalityCalculator createCardinalityCalculator() {
            return new KiWiCardinalityCalculator();
        }

        protected class KiWiCardinalityCalculator extends CardinalityCalculator {

            @Override
            protected double getCardinality(StatementPattern sp) {
                return super.getCardinality(sp);
            }

            protected Value getConstantValue(Var var) {
                return (var != null) ? var.getValue() : null;
            }
        }
    }

}
TOP

Related Classes of org.apache.marmotta.kiwi.versioning.sail.KiWiSnapshotConnection$KiWiTripleSource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.