Package de.linwave.gtm

Source Code of de.linwave.gtm.QueryImpl

package de.linwave.gtm;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.AbstractQueue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;

import org.odbms.FUNCTION;
import org.odbms.OP;
import org.odbms.ObjectContainer;
import org.odbms.ObjectSet;
import org.odbms.Predicate;
import org.odbms.Query;

import de.linwave.gtm.query.ObjectSetImpl;
import de.linwave.gtm.sort.AbstractSorter;
import de.linwave.gtm.sort.SORT;
import de.linwave.gtm.sort.SortItem;

public class QueryImpl<E> implements Query
{
  static final ObjectContainer db = GTM.getInstance();
  static final GTM gtm = GTM.getGTMInstance();

  protected Class<?> clasz;
  private List<Constraint> constrains = new ArrayList<Constraint>();
  private boolean executed;
  private boolean remote;

  /**
   *
   */
  QueryImpl() {
  }

  public QueryImpl(Class<?> clasz) {
    this(clasz, false);
  }

  /**
   *
   * @param clasz
   */
  public QueryImpl(Class<?> clasz, boolean remote) {
    this.clasz = clasz;
    this.remote = remote;
    constrain(new Constraint(clasz));
  }

  /**
   *
   * @param <E>
   * @param predicate
   */
  <E> QueryImpl(Predicate<E> predicate) {
    Method m = getFilterMethod(predicate);
    clasz = getExtentTypeFromGenericParameter(predicate);
    constrain(new Constraint(null, clasz, predicate));
  }

  /**
   *
   * @param <E>
   * @param predicate
   * @param comparator
   */
  <E> QueryImpl(Predicate<E> predicate, Comparator<E> comparator) {
    clasz = getExtentTypeFromGenericParameter(predicate);
    constrain(new Constraint(null, clasz, predicate, comparator));
  }

  /**
   *
   */
  public <E> ObjectSet<E> execute()
  {
    if (isRemote()) {
      System.out.println("***** REMOTE ******");
      return null;
    }

    executed = true;

    // Reorder Constraints
    // First the indexed fields
    List<Constraint> ordered = new ArrayList<Constraint>();
    for (Constraint constrain : constrains) {
      if (constrain.field != null && IndexUtils.isIndexed(clasz, constrain.field) && constrain.operator == OP.EQUALS) {
        ordered.add(constrain);
      }
    }

    for (Constraint constrain : constrains) {
      if (constrain.field != null && !ordered.contains(constrain) && IndexUtils.isIndexed(clasz, constrain.field) && constrain.operator == OP.STARTS_WITH) {
        ordered.add(constrain);
      }
    }

    // Indexed field != STARTS_WITH or EQUALS
    for (Constraint constrain : constrains) {
      if (constrain.field != null && !ordered.contains(constrain) && IndexUtils.isIndexed(clasz, constrain.field)) {
        ordered.add(constrain);
      }
    }

    // Now the un-indexed fields
    for (Constraint constrain : constrains) {
      if (constrain.field != null && constrain.operator != null && !ordered.contains(constrain)) {
        ordered.add(constrain);
      }
    }

    // Now with Predicates
    for (Constraint constrain : constrains) {
      if (constrain.predicate != null && !ordered.contains(constrain)) {
        ordered.add(constrain);
      }
    }

    // Now the SORT-ONLY constrains
    for (Constraint constrain : constrains) {
      if (constrain.sort != null && !ordered.contains(constrain)) {
        ordered.add(constrain);
      }
    }

    // Now the rest if no other constraints before
    if (ordered.isEmpty()) {
      for (Constraint constrain : constrains) {
        if (!ordered.contains(constrain)) {
          ordered.add(constrain);
        }
      }
    }

    // The constrains are now ordered
    constrains = ordered;

    // Connect the OUT to IN queues
    AbstractQueue<Long> q = null;

    // Check if we need a PriorityQueue (i.e. sortBy, native query with comparator)
    boolean haveComparator = false;
    for (Constraint constrain : constrains) {
      if (constrain.getComparator() != null) {
        haveComparator = true;
      }
    }

    // Start the constrain threads
    for (Constraint constraint : constrains) {
      // Connect the OUT to IN queue of the next constraint and execute
      constraint.queueIN = q;
      constraint.execute();
      q = constraint.queueOUT;
    }

    // Check if we have to wait for the last queue to complete
    boolean wait = false;
    wait = remote ? true : false;

    // Wait for query to complete
    // getLastConstraint().waitForCompleted();

    // Sort resulting queueOUT?
    for (Constraint constraint : constrains) {
      if (constraint.sort != null) {
        wait = true;
        break;
      }
    }

    if (wait) {
      getLastConstraint().waitForCompleted();
    }

    for (Constraint constraint : constrains) {
      if (constraint.sort != null) {
        AbstractQueue<Long> lastQueue = getLastConstraint().getQueueOUT();
        FieldInfo fi = ObjectTraverser.getFieldInfo(clasz, constraint.field);

        Object[] arr = new Object[lastQueue.size() - 1];
        int idx = 0;
        for (Long oid : lastQueue) {
          if (oid != GTM.END_OF_QUEUE) {
            String globalName = GlobalName.buildGlobalName(clasz, oid, constraint.field);
            SortItem item = new SortItem(oid, fi.typeHandler.get(gtm.GET(globalName)));
            arr[idx++] = item;
          }
        }

        // Sort the array
        AbstractSorter sorter = fi.typeHandler.getSorter();
        sorter.setSortDirection(constraint.sort);
        sorter.setLexicalSort(constraint.lexicalSort);
        Arrays.sort(arr, sorter);

        // Rebuild the queue with the sorted array
        AbstractQueue<Long> queue = new LinkedBlockingQueue<Long>();
        for (int i = 0; i < arr.length; i++) {
          queue.add(((SortItem) arr[i]).oid);
        }
        queue.add(GTM.END_OF_QUEUE);
        getLastConstraint().queueOUT = queue;
      }
    }

    //
    if (haveComparator) {
      ObjectSetImpl objSetImpl = new ObjectSetImpl<E>(clasz, getLastConstraint());
      Constraint constraint = getLastConstraint();
      constraint.waitForCompleted();

      Object[] arr = new Object[constraint.getQueueOUT().size() - 1];
      int idx = 0;
      AbstractQueue<Long> ql = constraint.getQueueOUT();
      // for (Long oid : constraint.getQueueOUT()) {
      for (Long oid : ql) {
        if (oid != GTM.END_OF_QUEUE) {
          arr[idx++] = (E) db.getByID(clasz, oid);
        }
      }

      Arrays.sort(arr, constraint.getComparator());

      Field oidField = ObjectTraverser.getFieldInfo(clasz, GTM.OID).field;
      AbstractQueue<Long> newOutQueue = new LinkedBlockingQueue<Long>();
      for (int i = 0; i < arr.length; i++) {
        E item = (E) arr[i];
        try {
          Long oid = (Long) oidField.get(item);
          newOutQueue.add(oid);
        } catch (Exception ex) {
          System.err.println(ex.getMessage());
        }
      }
      newOutQueue.add(GTM.END_OF_QUEUE);
      constraint.setQueueOUT(newOutQueue);
      return new ObjectSetImpl<E>(clasz, constraint);
    } else {
      return getObjectSet();
    }
  }

  /**
   *
   * @param <E>
   * @return
   */
  public <E> ObjectSet<E> getObjectSet()
  {
    return new ObjectSetImpl<E>(clasz, getLastConstraint());
  }

  /**
   *
   */
  public Constraint constrain(Class<?> clasz)
  {
    this.clasz = clasz;
    Constraint constraint = new Constraint(clasz);
    constrain(constraint);
    return constraint;
  }

  /**
   *
   * @param constraint
   * @return
   */
  public Constraint constrain(Constraint constraint)
  {
    constrains.add(constraint);
    return constraint;
  }

  /**
   * Sort ascending with default lexicalSort (the, The)
   *
   * @param field
   * @return
   */
  public Constraint sortBy(String field)
  {
    return sortBy(field, true);
  }

  public Constraint sortBy(String field, boolean lexicalSort)
  {
    AbstractQueue<Long> queue = getLastConstraint().queueOUT;
    Constraint c = new Constraint(queue, clasz, field, SORT.ASCENDING, lexicalSort);
    constrains.add(c);
    return c;
  }

  /**
   * Sort descending with default lexicalSort (the, The)
   */
  public Constraint sortByDescending(String field)
  {
    return sortByDescending(field, true);
  }

  /**
   * Sort by field
   *
   * @param field
   * @return
   */
  public Constraint sortByDescending(String field, boolean lexicalSort)
  {
    AbstractQueue<Long> queue = getLastConstraint().queueOUT;
    Constraint c = new Constraint(queue, clasz, field, SORT.DESCENDING, lexicalSort);
    constrains.add(c);
    return c;
  }

  /**
   *
   * @param field
   * @param operator
   * @param value
   * @return
   */
  public Constraint constrain(String field, OP operator, Object... value)
  {
    return constrain(field, operator, null, value);
  }

  /**
   *
   * @param field
   * @param operator
   * @param function
   * @param value
   * @return
   */
  public Constraint constrain(String field, OP operator, FUNCTION function, Object... value)
  {
    AbstractQueue<Long> queue = getLastConstraint().queueOUT;

    Constraint c = new Constraint(queue, clasz, field, operator, function, value);
    constrains.add(c);

    return c;
  }

  /**
   *
   * @return
   */
  public List<Constraint> getConstraints()
  {
    return constrains;
  }

  /**
   *
   * @param p
   */
  public <E> ObjectSet<E> AND(Query p)
  {
    QueryImpl qi = (QueryImpl) p;
    waitForQueue(this);
    waitForQueue(qi);

    AbstractQueue<Long> q1 = (AbstractQueue<Long>) getOUTQueue();
    AbstractQueue<Long> q2 = (AbstractQueue<Long>) qi.getOUTQueue();
    q1.retainAll(q2);

    return getObjectSet();
  }

  /**
   *
   * @param p
   */
  public <E> ObjectSet<E> OR(Query p)
  {
    QueryImpl qi = (QueryImpl) p;
    waitForQueue(this);
    waitForQueue(qi);

    AbstractQueue<Long> q1 = (AbstractQueue<Long>) getOUTQueue();
    AbstractQueue<Long> q2 = (AbstractQueue<Long>) qi.getOUTQueue();

    AbstractQueue<Long> newQueue = new LinkedBlockingQueue<Long>();
    if (q1.size() > q2.size()) {
      newQueue.addAll(q1);
      addToQueue(newQueue, q2);
    } else {
      newQueue.addAll(q2);
      addToQueue(newQueue, q1);
    }

    return getObjectSet();
  }

  /**
   * Add a long to the current queueOUT if it doesn't exists.
   *
   * @param l
   * @return true if the long was added, false otherwise
   */
  private void addToQueue(AbstractQueue<Long> destination, AbstractQueue<Long> source)
  {
    int i = 0, j = 0;

    for (Long oid : source) {
      i++;
      if (!destination.contains(oid)) {
        destination.add(oid);
        j++;
      }
    }
    while (destination.remove(GTM.END_OF_QUEUE)) {
      ;
    }
    destination.add(GTM.END_OF_QUEUE);
    setOUTQueue(destination);
  }

  /**
   *
   * @return
   */
  protected AbstractQueue<Long> getOUTQueue()
  {
    Constraint c = getLastConstraint();
    return c.queueOUT;
  }

  /**
   *
   * @return
   */
  protected Constraint getLastConstraint()
  {
    return constrains.get(constrains.size() - 1);
  }

  /**
   * Overwrite the queue from the FIRST constraint in an AND or OR operation
   *
   * @param q
   */
  public void setOUTQueue(AbstractQueue<Long> q)
  {
    getLastConstraint().queueOUT = q;
  }

  /**
   *
   * @param query
   */
  private void waitForQueue(QueryImpl query)
  {
    int waits = 0;

    if (!query.executed) {
      query.execute();
    }

    Constraint constraint = query.getLastConstraint();

    while (!constraint.isCompleted()) {
      waits++;
      GTMUtils.sleep(25);
    }
  }

  // =================== Predicate stuff ========================

  private Class<E> getExtentTypeFromGenericParameter(Predicate predicate)
  {
    Class<E> extentType = (Class<E>) getFilterMethod(predicate).getParameterTypes()[0];
    try {
      Type genericType = ((ParameterizedType) predicate.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
      if ((genericType instanceof Class) && (extentType.isAssignableFrom((Class) genericType))) {
        extentType = (Class<E>) genericType;
      }
    } catch (RuntimeException e) {
    }
    return extentType;
  }

  /**
   *
   * @return
   */
  private Method getFilterMethod(Predicate predicate)
  {
    Method method = null;

    Method[] methods = predicate.getClass().getMethods();
    for (int methodIdx = 0; methodIdx < methods.length; methodIdx++) {
      method = methods[methodIdx];
      if ((!method.getName().equals("match")) || method.getParameterTypes().length != 1) {
        continue;
      }
      String targetName = method.getParameterTypes()[0].getName();
      if (!"java.lang.Object".equals(targetName)) {
        break;
      }
    }
    if (method == null) {
      throw new IllegalArgumentException("Invalid predicate.");
    }
    return method;
  }

  // =================== Predicate stuff ========================

  /**
   *
   */
  public void printConstraintInfo()
  {
    System.out.println("---------- Constraints ----------");
    for (Constraint constrain : getConstraints()) {
      System.out.println(constrain);
    }
  }

  public boolean isRemote()
  {
    return remote;
  }
}
TOP

Related Classes of de.linwave.gtm.QueryImpl

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.