Package uk.ac.open.kmi.smartproducts.sesame.sail

Source Code of uk.ac.open.kmi.smartproducts.sesame.sail.AndroidNativeStoreConnection

/*
* Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2009.
*
* Licensed under the Aduna BSD-style license.
*/
package uk.ac.open.kmi.smartproducts.sesame.sail;

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

import info.aduna.concurrent.locks.Lock;
import info.aduna.iteration.CloseableIteration;
import info.aduna.iteration.CloseableIteratorIteration;
import info.aduna.iteration.ExceptionConvertingIteration;
import info.aduna.iteration.Iterations;

import org.openrdf.OpenRDFUtil;
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.impl.NamespaceImpl;
import org.openrdf.query.BindingSet;
import org.openrdf.query.Dataset;
import org.openrdf.query.QueryEvaluationException;
import org.openrdf.query.algebra.QueryRoot;
import org.openrdf.query.algebra.TupleExpr;
import org.openrdf.query.algebra.Var;
import org.openrdf.query.algebra.evaluation.impl.BindingAssigner;
import org.openrdf.query.algebra.evaluation.impl.CompareOptimizer;
import org.openrdf.query.algebra.evaluation.impl.ConjunctiveConstraintSplitter;
import org.openrdf.query.algebra.evaluation.impl.ConstantOptimizer;
import org.openrdf.query.algebra.evaluation.impl.DisjunctiveConstraintOptimizer;
import org.openrdf.query.algebra.evaluation.impl.EvaluationStrategyImpl;
import org.openrdf.query.algebra.evaluation.impl.FilterOptimizer;
import org.openrdf.query.algebra.evaluation.impl.IterativeEvaluationOptimizer;
import org.openrdf.query.algebra.evaluation.impl.OrderLimitOptimizer;
import org.openrdf.query.algebra.evaluation.impl.QueryJoinOptimizer;
import org.openrdf.query.algebra.evaluation.impl.QueryModelNormalizer;
import org.openrdf.query.algebra.evaluation.impl.SameTermFilterOptimizer;
import org.openrdf.query.algebra.helpers.QueryModelVisitorBase;
import org.openrdf.query.impl.EmptyBindingSet;
import org.openrdf.sail.SailException;
import org.openrdf.sail.helpers.DefaultSailChangedEvent;
import org.openrdf.sail.helpers.NotifyingSailConnectionBase;
import org.openrdf.sail.inferencer.InferencerConnection;
import uk.ac.open.kmi.smartproducts.sesame.sail.btree.RecordIterator;
import uk.ac.open.kmi.smartproducts.sesame.sail.model.NativeValue;

/**
* @author Arjohn Kampman
*/
public class AndroidNativeStoreConnection extends NotifyingSailConnectionBase implements InferencerConnection {

  /*-----------*
   * Constants *
   *-----------*/

  protected final AndroidNativeStore nativeStore;

  /*-----------*
   * Variables *
   *-----------*/

  private volatile DefaultSailChangedEvent sailChangedEvent;

  /**
   * The exclusive transaction lock held by this connection during
   * transactions.
   */
  private volatile Lock txnLock;

  /*--------------*
   * Constructors *
   *--------------*/

  protected AndroidNativeStoreConnection(AndroidNativeStore nativeStore)
    throws IOException
  {
    super(nativeStore);
    this.nativeStore = nativeStore;
    sailChangedEvent = new DefaultSailChangedEvent(nativeStore);
  }

  /*---------*
   * Methods *
   *---------*/

  @Override
  protected void closeInternal() {
    // FIXME we should check for open iteration objects.
  }

  @Override
  protected CloseableIteration<? extends BindingSet, QueryEvaluationException> evaluateInternal(
      TupleExpr tupleExpr, Dataset dataset, BindingSet bindings, boolean includeInferred)
    throws SailException
  {
    logger.trace("Incoming query model:\n{}", tupleExpr);

    // 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 {
      replaceValues(tupleExpr);

      NativeTripleSource tripleSource = new NativeTripleSource(nativeStore, includeInferred,
          transactionActive());
      EvaluationStrategyImpl 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 NativeEvaluationStatistics(nativeStore)).optimize(tupleExpr, dataset,
          bindings);
      new IterativeEvaluationOptimizer().optimize(tupleExpr, dataset, bindings);
      new FilterOptimizer().optimize(tupleExpr, dataset, bindings);
      new OrderLimitOptimizer().optimize(tupleExpr, dataset, bindings);

      logger.trace("Optimized query model:\n{}", tupleExpr);

      return strategy.evaluate(tupleExpr, EmptyBindingSet.getInstance());
    }
    catch (QueryEvaluationException e) {
      throw new SailException(e);
    }
  }

  protected void replaceValues(TupleExpr tupleExpr)
    throws SailException
  {
    // Replace all Value objects stored in variables with NativeValue objects,
    // which cache internal IDs
    tupleExpr.visit(new QueryModelVisitorBase<SailException>() {

      @Override
      public void meet(Var var) {
        if (var.hasValue()) {
          var.setValue(nativeStore.getValueStore().getNativeValue(var.getValue()));
        }
      }
    });
  }

  @Override
  protected CloseableIteration<? extends Resource, SailException> getContextIDsInternal()
    throws SailException
  {
    // Which resources are used as context identifiers is not stored
    // separately. Iterate over all statements and extract their context.
    try {
      CloseableIteration<? extends Resource, IOException> contextIter = nativeStore.getContextIDs(transactionActive());

      return new ExceptionConvertingIteration<Resource, SailException>(contextIter) {

        @Override
        protected SailException convert(Exception e) {
          if (e instanceof IOException) {
            return new SailException(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 (IOException e) {
      throw new SailException(e);
    }
  }

  @Override
  protected CloseableIteration<? extends Statement, SailException> getStatementsInternal(Resource subj,
      URI pred, Value obj, boolean includeInferred, Resource... contexts)
    throws SailException
  {
    try {
      CloseableIteration<? extends Statement, IOException> iter = nativeStore.createStatementIterator(
          subj, pred, obj, includeInferred, transactionActive(), contexts);

      return new ExceptionConvertingIteration<Statement, SailException>(iter) {

        @Override
        protected SailException convert(Exception e) {
          if (e instanceof IOException) {
            return new SailException(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 (IOException e) {
      throw new SailException("Unable to get statements", e);
    }
  }

  @Override
  protected long sizeInternal(Resource... contexts)
    throws SailException
  {
    OpenRDFUtil.verifyContextNotNull(contexts);

    try {
      List<Integer> contextIDs;
      if (contexts.length == 0) {
        contextIDs = Arrays.asList(NativeValue.UNKNOWN_ID);
      }
      else {
        contextIDs = nativeStore.getContextIDs(contexts);
      }

      long size = 0L;

      for (int contextID : contextIDs) {
        // Iterate over all explicit statements
        RecordIterator iter = nativeStore.getTripleStore().getTriples(-1, -1, -1, contextID, true,
            transactionActive());
        try {
          while (iter.next() != null) {
            size++;
          }
        }
        finally {
          iter.close();
        }
      }

      return size;
    }
    catch (IOException e) {
      throw new SailException(e);
    }
  }

  @Override
  protected CloseableIteration<? extends Namespace, SailException> getNamespacesInternal()
    throws SailException
  {
    return new CloseableIteratorIteration<NamespaceImpl, SailException>(
        nativeStore.getNamespaceStore().iterator());
  }

  @Override
  protected String getNamespaceInternal(String prefix)
    throws SailException
  {
    return nativeStore.getNamespaceStore().getNamespace(prefix);
  }

  @Override
  protected void startTransactionInternal()
    throws SailException
  {
    txnLock = nativeStore.getTransactionLock();

    try {
      nativeStore.getTripleStore().startTransaction();
    }
    catch (IOException e) {
      txnLock.release();
      throw new SailException(e);
    }
    catch (RuntimeException e) {
      txnLock.release();
      throw e;
    }
  }

  @Override
  protected void commitInternal()
    throws SailException
  {
    try {
      nativeStore.getValueStore().sync();
      nativeStore.getNamespaceStore().sync();
      nativeStore.getTripleStore().commit();

      txnLock.release();
    }
    catch (IOException e) {
      throw new SailException(e);
    }
    catch (RuntimeException e) {
      logger.error("Encountered an unexpected problem while trying to commit", e);
      throw e;
    }

    nativeStore.notifySailChanged(sailChangedEvent);

    // create a fresh event object.
    sailChangedEvent = new DefaultSailChangedEvent(nativeStore);
  }

  @Override
  protected void rollbackInternal()
    throws SailException
  {
    try {
      nativeStore.getValueStore().sync();
      nativeStore.getTripleStore().rollback();
    }
    catch (IOException e) {
      throw new SailException(e);
    }
    catch (RuntimeException e) {
      logger.error("Encountered an unexpected problem while trying to roll back", e);
      throw e;
    }
    finally {
      txnLock.release();
    }
  }

  @Override
  protected void addStatementInternal(Resource subj, URI pred, Value obj, Resource... contexts)
    throws SailException
  {
    addStatement(subj, pred, obj, true, contexts);
  }

  public boolean addInferredStatement(Resource subj, URI pred, Value obj, Resource... contexts)
    throws SailException
  {
    connectionLock.readLock().lock();
    try {
      verifyIsOpen();

      updateLock.lock();
      try {
        autoStartTransaction();
        return addStatement(subj, pred, obj, false, contexts);
      }
      finally {
        updateLock.unlock();
      }
    }
    finally {
      connectionLock.readLock().unlock();
    }
  }

  private boolean addStatement(Resource subj, URI pred, Value obj, boolean explicit, Resource... contexts)
    throws SailException
  {
    OpenRDFUtil.verifyContextNotNull(contexts);

    boolean result = false;

    try {
      ValueStore valueStore = nativeStore.getValueStore();
      int subjID = valueStore.storeValue(subj);
      int predID = valueStore.storeValue(pred);
      int objID = valueStore.storeValue(obj);

      if (contexts.length == 0) {
        contexts = new Resource[] { null };
      }

      for (Resource context : contexts) {
        int contextID = 0;
        if (context != null) {
          contextID = valueStore.storeValue(context);
        }

        boolean wasNew = nativeStore.getTripleStore().storeTriple(subjID, predID, objID, contextID,
            explicit);
        result |= wasNew;

        if (wasNew) {
          // The triple was not yet present in the triple store
          sailChangedEvent.setStatementsAdded(true);

          if (hasConnectionListeners()) {
            Statement st;

            if (context != null) {
              st = valueStore.createStatement(subj, pred, obj, context);
            }
            else {
              st = valueStore.createStatement(subj, pred, obj);
            }

            notifyStatementAdded(st);
          }
        }
      }
    }
    catch (IOException e) {
      throw new SailException(e);
    }
    catch (RuntimeException e) {
      logger.error("Encountered an unexpected problem while trying to add a statement", e);
      throw e;
    }

    return result;
  }

  @Override
  protected void removeStatementsInternal(Resource subj, URI pred, Value obj, Resource... contexts)
    throws SailException
  {
    removeStatements(subj, pred, obj, true, contexts);
  }

  public boolean removeInferredStatement(Resource subj, URI pred, Value obj, Resource... contexts)
    throws SailException
  {
    connectionLock.readLock().lock();
    try {
      verifyIsOpen();

      updateLock.lock();
      try {
        autoStartTransaction();
        int removeCount = removeStatements(subj, pred, obj, false, contexts);
        return removeCount > 0;
      }
      finally {
        updateLock.unlock();
      }
    }
    finally {
      connectionLock.readLock().unlock();
    }
  }

  private int removeStatements(Resource subj, URI pred, Value obj, boolean explicit, Resource... contexts)
    throws SailException
  {
    OpenRDFUtil.verifyContextNotNull(contexts);

    try {
      TripleStore tripleStore = nativeStore.getTripleStore();
      ValueStore valueStore = nativeStore.getValueStore();

      int subjID = NativeValue.UNKNOWN_ID;
      if (subj != null) {
        subjID = valueStore.getID(subj);
        if (subjID == NativeValue.UNKNOWN_ID) {
          return 0;
        }
      }
      int predID = NativeValue.UNKNOWN_ID;
      if (pred != null) {
        predID = valueStore.getID(pred);
        if (predID == NativeValue.UNKNOWN_ID) {
          return 0;
        }
      }
      int objID = NativeValue.UNKNOWN_ID;
      if (obj != null) {
        objID = valueStore.getID(obj);
        if (objID == NativeValue.UNKNOWN_ID) {
          return 0;
        }
      }

      List<Integer> contextIDList = new ArrayList<Integer>(contexts.length);
      if (contexts.length == 0) {
        contextIDList.add(NativeValue.UNKNOWN_ID);
      }
      else {
        for (Resource context : contexts) {
          if (context == null) {
            contextIDList.add(0);
          }
          else {
            int contextID = valueStore.getID(context);
            if (contextID != NativeValue.UNKNOWN_ID) {
              contextIDList.add(contextID);
            }
          }
        }
      }

      int removeCount = 0;

      for (int i = 0; i < contextIDList.size(); i++) {
        int contextID = contextIDList.get(i);

        List<Statement> removedStatements = Collections.emptyList();

        if (hasConnectionListeners()) {
          // We need to iterate over all matching triples so that they can
          // be reported
          RecordIterator btreeIter = tripleStore.getTriples(subjID, predID, objID, contextID, explicit,
              true);

          NativeStatementIterator iter = new NativeStatementIterator(btreeIter, valueStore);

          removedStatements = Iterations.asList(iter);
        }

        removeCount += tripleStore.removeTriples(subjID, predID, objID, contextID, explicit);

        for (Statement st : removedStatements) {
          notifyStatementRemoved(st);
        }
      }

      if (removeCount > 0) {
        sailChangedEvent.setStatementsRemoved(true);
      }

      return removeCount;
    }
    catch (IOException e) {
      throw new SailException(e);
    }
    catch (RuntimeException e) {
      logger.error("Encountered an unexpected problem while trying to remove statements", e);
      throw e;
    }
  }

  @Override
  protected void clearInternal(Resource... contexts)
    throws SailException
  {
    removeStatements(null, null, null, true, contexts);
  }

  public void clearInferred(Resource... contexts)
    throws SailException
  {
    connectionLock.readLock().lock();
    try {
      verifyIsOpen();

      updateLock.lock();
      try {
        autoStartTransaction();
        removeStatements(null, null, null, false, contexts);
      }
      finally {
        updateLock.unlock();
      }
    }
    finally {
      connectionLock.readLock().unlock();
    }
  }

  public void flushUpdates() {
    // no-op; changes are reported as soon as they come in
  }

  @Override
  protected void setNamespaceInternal(String prefix, String name)
    throws SailException
  {
    nativeStore.getNamespaceStore().setNamespace(prefix, name);
  }

  @Override
  protected void removeNamespaceInternal(String prefix)
    throws SailException
  {
    nativeStore.getNamespaceStore().removeNamespace(prefix);
  }

  @Override
  protected void clearNamespacesInternal()
    throws SailException
  {
    nativeStore.getNamespaceStore().clear();
  }
}
TOP

Related Classes of uk.ac.open.kmi.smartproducts.sesame.sail.AndroidNativeStoreConnection

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.