Package com.dooapp.gaedo.blueprints

Source Code of com.dooapp.gaedo.blueprints.CacheLoader

package com.dooapp.gaedo.blueprints;

import java.beans.PropertyChangeEvent;
import java.util.EmptyStackException;

import javax.persistence.CascadeType;

import com.dooapp.gaedo.blueprints.operations.Loader;
import com.dooapp.gaedo.blueprints.queries.BluePrintsQueryBuilder;
import com.dooapp.gaedo.blueprints.queries.DataTypeIterable;
import com.dooapp.gaedo.blueprints.queries.executable.GraphExecutableQuery;
import com.dooapp.gaedo.blueprints.utils.VertexPathNavigator;
import com.dooapp.gaedo.blueprints.utils.VertexPathNavigator.VertexLocation;
import com.dooapp.gaedo.exceptions.range.BadRangeDefinitionException;
import com.dooapp.gaedo.exceptions.range.BadStartIndexException;
import com.dooapp.gaedo.finders.FieldInformer;
import com.dooapp.gaedo.finders.Informer;
import com.dooapp.gaedo.finders.QueryBrowser;
import com.dooapp.gaedo.finders.QueryBuilder;
import com.dooapp.gaedo.finders.QueryExpression;
import com.dooapp.gaedo.finders.QueryExpressionContainerVisitor;
import com.dooapp.gaedo.finders.QueryExpressionContainerVisitorAdapter;
import com.dooapp.gaedo.finders.QueryStatement;
import com.dooapp.gaedo.finders.SortingBuilder;
import com.dooapp.gaedo.finders.SortingExpression;
import com.dooapp.gaedo.finders.expressions.EqualsExpression;
import com.dooapp.gaedo.finders.projection.NoopProjectionBuilder;
import com.dooapp.gaedo.finders.projection.ProjectionBuilder;
import com.dooapp.gaedo.finders.projection.ValueFetcher;
import com.dooapp.gaedo.finders.repository.ServiceRepository;
import com.dooapp.gaedo.finders.sort.SortingExpressionImpl;
import com.dooapp.gaedo.properties.Property;
import com.tinkerpop.blueprints.IndexableGraph;
import com.tinkerpop.blueprints.Vertex;

public class GraphQueryStatement<
    ValueType,
    DataType,
    InformerType extends Informer<DataType>>
  implements QueryStatement<ValueType, DataType, InformerType> {

  /**
   * Object allowing execution of a projection from an input vertex to the given result.
   * @author ndx
   *
   */
  public class ProjectionExecutor {
    /**
     * Fetches values for properties from given vertex
     * @author ndx
     *
     */
    private class GraphValueFetcher implements ValueFetcher {

      private Vertex input;

      public GraphValueFetcher(Vertex input) {
        this.input = input;
      }

      @Override
      public <Type> Type getValue(FieldInformer<Type> propertyDescriptor) {
        VertexPathNavigator navigator = new VertexPathNavigator(service.getStrategy(), input);
        VertexLocation destination = navigator.navigateOn(propertyDescriptor.getFieldPath());

        Vertex destinationVertex = destination.vertex();
        try {
          // There may remain one unevaluated property - in which case it's a literal one
          Property destinationProperty = destination.property();
          Loader loader = new Loader();
          if(loader.hasLiteralProperty(destinationProperty, destinationVertex)) {
            return (Type) loader.loadSingleLiteral(getClass().getClassLoader(), destinationProperty, destinationVertex, cache);
          }
        } catch(EmptyStackException e) {

        }
        return (Type) service.loadObject(destinationVertex, cache);
      }

    }

    private ObjectCache cache = createPrepopulatedCache();

    public ValueType get(Vertex input) {
      return projector.project(service.getInformer(), getFetcherFor(input));
    }

    private ValueFetcher getFetcherFor(Vertex input) {
      return new GraphValueFetcher(input);
    }

  }

  protected QueryBuilder<? super InformerType> query;
  protected AbstractBluePrintsBackedFinderService<? extends IndexableGraph, DataType, InformerType> service;
  protected ServiceRepository repository;

  public GraphQueryStatement(QueryBuilder<? super InformerType> query,
          AbstractBluePrintsBackedFinderService<? extends IndexableGraph, DataType, InformerType> service,
          ServiceRepository repository) {
    this.query = query;
    this.service = service;
    this.repository = repository;
    this.state = State.INITIAL;
  }

  /**
   * Query id, can be used for debugging
   */
  private String id;
  /**
   * Query execution state
   */
  protected State state;
  /**
   * Sorting expression used to define sort criterias
   */
  private SortingExpression sortingExpression = new SortingExpressionImpl();
  private QueryExpression filterExpression;
  /**
   * Projector used to transform browsed vertices into a meaningful result. Notice default value is always the noop projection builder
   */
  private ProjectionBuilder<ValueType, DataType, InformerType> projector = new NoopProjectionBuilder();

  private GraphExecutableQuery prepareQuery() {
    try {
      if (QueryLog.logger.isLoggable(QueryLog.QUERY_LOGGING_LEVEL)) {
        QueryLog.logger.log(QueryLog.QUERY_LOGGING_LEVEL, "preparing query "+id);
      }
      BluePrintsQueryBuilder<DataType, InformerType> builder = createQueryBuilder(service);
      InformerType informer = service.getInformer();
      filterExpression = query.createMatchingExpression(informer);
      filterExpression.accept(builder);
      if (QueryLog.logger.isLoggable(QueryLog.QUERY_LOGGING_LEVEL)) {
        QueryLog.logger.log(QueryLog.QUERY_LOGGING_LEVEL, "filering expression for "+id+" is "+filterExpression);
      }
      return builder.getQuery(sortingExpression);
    } finally {
      if (QueryLog.logger.isLoggable(QueryLog.QUERY_LOGGING_LEVEL)) {
        QueryLog.logger.log(QueryLog.QUERY_LOGGING_LEVEL, "query "+id+" is constructed and usable ... now matching");
      }
      setState(State.MATCHING);
    }
  }

  protected BluePrintsQueryBuilder<DataType, InformerType> createQueryBuilder(AbstractBluePrintsBackedFinderService<? extends IndexableGraph, DataType, InformerType> service) {
    return new BluePrintsQueryBuilder<DataType, InformerType>(service);
  }

  @Override
  public int count() {
    try {
      return prepareQuery().count();
    } finally {
      setState(State.EXECUTED);
    }
  }

  @Override
  public Iterable<ValueType> get(int start, int end) {
    try {
      if (start < 0) {
        throw new BadStartIndexException(start);
      } else if (end < start) {
        throw new BadRangeDefinitionException(start, end);
      }
      Iterable<Vertex> vertices = prepareQuery().get(start, end);
      return createResultsIterable(vertices);
    } finally {
      setState(State.EXECUTED);
    }
  }

  /**
   * Create result iterable from the vertex iterables.
   * @param iterable list of vertex to navigate
   * @return
   */
  private DataTypeIterable<ValueType> createResultsIterable(Iterable<Vertex> iterable) {
    return new DataTypeIterable<ValueType>(iterable, new ProjectionExecutor());
  }

  private ObjectCache createPrepopulatedCache() {
    final ObjectCache cache = ObjectCache.create(CascadeType.REFRESH);
    class CacheLoader extends QueryExpressionContainerVisitorAdapter {

      /**
       * @param expression
       * @see com.dooapp.gaedo.finders.expressions.QueryExpressionVisitorAdapter#visit(com.dooapp.gaedo.finders.expressions.EqualsExpression)
       */
      @Override
      public void visit(EqualsExpression expression) {
        Object equalsValue = expression.getValue();
        putInCache(cache, equalsValue);
      }

      @SuppressWarnings({ "unchecked", "rawtypes" })
      private void putInCache(final ObjectCache cache, Object equalsValue) {
        if(equalsValue!=null) {
          // Object class is in repository, so try to find its object key to put it in cache
          Class<?> objectClass = equalsValue.getClass();
          if(repository.containsKey(objectClass)) {
            AbstractBluePrintsBackedFinderService service = (AbstractBluePrintsBackedFinderService) repository.get(objectClass);
            String objectId = service.getIdVertexId(equalsValue, false);
            cache.put(objectId, equalsValue);
          }
        }
      }

    }
    CacheLoader loader = new CacheLoader();
    filterExpression.accept(loader);
    sortingExpression.accept(loader);
    // Now cache is populated
    return cache;
  }

  @Override
  public Iterable<ValueType> getAll() {
    try {
      Iterable<Vertex> vertices = prepareQuery().getAll();
      return createResultsIterable(vertices);
    } finally {
      setState(State.EXECUTED);
    }
  }

  @Override
  public ValueType getFirst() {
    try {
      Vertex result = prepareQuery().getVertex();
      if (result == null)
        throw new NoReturnableVertexException(filterExpression);
      return new ProjectionExecutor().get(result);
    } finally {
      setState(State.EXECUTED);
    }
  }

  @Override
  public QueryStatement<ValueType, DataType, InformerType> sortBy(SortingBuilder<InformerType> expression) {
    try {
      this.sortingExpression = expression.createSortingExpression(service
          .getInformer());
      return this;
    } finally {
      setState(State.SORTING);
    }
  }

  @Override
  public void accept(QueryExpressionContainerVisitor visitor) {
    visitor.startVisit(this);
    filterExpression.accept(visitor);
    sortingExpression.accept(visitor);
    visitor.endVisit(this);
  }

  @Override
  public State getState() {
    return state;
  }

  @Override
  public String getId() {
    return id;
  }

  @Override
  public void setId(String id) {
    this.id = id;
  }

  /**
   * @param state the state to set
   * @category setter
   * @category state
   */
  public void setState(State state) {
    if(this.state!=state) {
      // Special construct allowing some very weird behaviour (like getting execution time for a query, I think)
      State old = this.state;
      this.state = state;
      repository.getSupport().firePropertyChange(
          new PropertyChangeEvent(this, QueryStatement.STATE_PROPERTY,
              old, state));
    }
  }

  @Override
  public <ProjectedValueType> QueryBrowser<ProjectedValueType> projectOn(ProjectionBuilder<ProjectedValueType, DataType, InformerType> projector) {
    GraphQueryStatement<ProjectedValueType, DataType, Informer<DataType>> returned = new GraphQueryStatement(query, service, repository);
    returned.projector = (ProjectionBuilder<ProjectedValueType, DataType, Informer<DataType>>) projector;
    return returned;
  }

}
TOP

Related Classes of com.dooapp.gaedo.blueprints.CacheLoader

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.