Package de.linwave.gtm

Source Code of de.linwave.gtm.Constraint

package de.linwave.gtm;

import java.util.AbstractQueue;
import java.util.Comparator;
import java.util.Date;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger;

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

import de.linwave.gtm.query.FUNCTIONImpl;
import de.linwave.gtm.query.OPImpl;
import de.linwave.gtm.query.Range;
import de.linwave.gtm.sort.SORT;

public class Constraint extends Thread
{
  private static Logger logger = Logger.getLogger(Constraint.class.getName());
  private static GTM gtm = GTM.getGTMInstance();
  private static ObjectContainer session = GTM.getInstance();

  private static final int MAX_POLL_CYCLES = 500;

  AbstractQueue<Long> queueIN;
  AbstractQueue<Long> queueOUT = new LinkedBlockingQueue<Long>();
  // AbstractQueue<Long> queueOUT = new ArrayBlockingQueue<Long>(QueryImpl.MAX_QUEUE_SIZE);
  // AbstractQueue<Long> queueOUT = new PriorityBlockingQueue<Long>();
  String field;
  OP operator;
  SORT sort;
  boolean lexicalSort;
  Predicate predicate;

  private Comparator<?> comparator;
  private Class<?> clasz;
  private FUNCTION function;
  private Object value;
  private Range range;
  private boolean bypass;
  private boolean completed;

  private int polled = 0;
  private int offered = 0;
  private boolean notified;

  /**
   *
   * @param clasz
   */
  protected Constraint(Class<?> clasz) {
    this.clasz = clasz;
  }

  /**
   * A 'field' constrain implies 'sort by field'
   *
   * @param queueIN
   * @param clasz
   * @param field
   */
  public Constraint(AbstractQueue<Long> queueIN, Class<?> clasz, String field, SORT sort, boolean lexicalSort) {
    this.queueIN = queueIN;
    this.clasz = clasz;
    this.field = field;
    this.sort = sort;
    this.lexicalSort = lexicalSort;
  }

  /**
   *
   * @param queueIN
   * @param clasz
   * @param field
   * @param operator
   * @param function
   * @param value
   */
  public Constraint(AbstractQueue<Long> queueIN, Class<?> clasz, String field, OP operator, FUNCTION function, Object... objs) {
    this.queueIN = queueIN;
    this.clasz = clasz;
    this.field = field;
    this.operator = operator;
    this.function = function;

    if (operator == OP.RANGE) {
      int cnt = 0;
      Object from = null;
      Object to = null;

      for (Object obj : objs) {
        if (cnt == 0)
          from = obj;
        else if (cnt == 1)
          to = obj;
        cnt++;
      }
      range = new Range(from, to);

    } else {
      for (Object obj : objs) {
        if (obj instanceof Date) {
          obj = ((Date) obj).getTime();
        }
        this.value = (function == null) ? obj : FUNCTIONImpl.eval(function, (String) obj);
        break;
      }
    }
  }

  /**
   *
   * @param queueIN
   * @param predicate
   */
  public Constraint(AbstractQueue<Long> queueIN, Class<?> clasz, Predicate<?> predicate) {
    this(queueIN, clasz, predicate, null);
  }

  /**
   *
   * @param queueIN
   * @param predicate
   * @param comparator
   */
  public Constraint(AbstractQueue<Long> queueIN, Class<?> clasz, Predicate<?> predicate, Comparator<?> comparator) {
    this.queueIN = queueIN;
    this.predicate = predicate;
    this.clasz = clasz;
    this.comparator = comparator;
  }

  /**
   * Start the thread Will be called from POQL.execute()
   */
  public void execute()
  {
    this.start();
  }

  /**
   *
   */
  public void run()
  {
    if (queueIN != null) {
      processINQueue();
    } else {
      boolean isIndexed = IndexUtils.isIndexed(clasz, field);
      if (isIndexed) {
        if (range != null)
          processIndexWithRange();
        else
          processIndex();
      } else {
        fullTableScan();
      }
    }
  }

  /**
   *
   */
  private void processIndex()
  {
    long oid;
    String key;
    String gln;
    bypass = true; // Do not evaluate again

    logger.info("Process index class=" + clasz.getName() + " field=" + field + " value=" + value);

    // Index name
    String classGlobalNameIDX = GlobalName.Class2GlobalName(clasz) + "I";
    String normalizedValue = IndexUtils.normalizeIndexKey(value);

    if (operator == OP.EQUALS) { // Index scan with exact starting value
      gln = GlobalName.buildGlobalName(classGlobalNameIDX, field, normalizedValue);
      String oidKey = GlobalName.buildGlobalName(classGlobalNameIDX, field, normalizedValue, "");

      while ((oidKey = gtm.ORDER(oidKey)) != null) {
        oid = Long.parseLong(oidKey);
        offer(oid);
        oidKey = GlobalName.buildGlobalName(classGlobalNameIDX, field, normalizedValue, oid);
      }
      markEndOfQueue();
      return;

    } else if (operator == OP.STARTS_WITH || operator == OP.GREATER) { // Index scan with given starting value
      gln = GlobalName.buildGlobalName(classGlobalNameIDX, field, normalizedValue);

    } else if (operator == OP.CONTAINS || operator == OP.ENDS_WITH || operator == OP.SMALLER) { // Full index scan
      gln = GlobalName.buildGlobalName(classGlobalNameIDX, field, -1);

    } else {
      throw new RuntimeException("Invalid Operation. Supported is only STARTS_WITH, ENDS_WITH, CONTAINS, EQUALS, GREATER, SMALLER on index");
    }

    int count = 0;

    try {
      while ((key = gtm.ORDER(gln)) != null) {
        // No more items?
        if (key == null)
          break;
        if (operator == OP.STARTS_WITH && !key.startsWith(normalizedValue))
          break;

        count++;

        boolean addItem;
        if (value instanceof String)
          addItem = OPImpl.eval(operator, key, normalizedValue);
        else
          addItem = OPImpl.eval(operator, key, value);

        gln = GlobalName.buildGlobalName(classGlobalNameIDX, field, key);

        if (addItem) {
          String oidKey = GlobalName.buildGlobalName(classGlobalNameIDX, field, key, -1);
          while ((oidKey = gtm.ORDER(oidKey)) != null) {
            oid = Long.parseLong(oidKey);
            offer(oid);
            oidKey = GlobalName.buildGlobalName(classGlobalNameIDX, field, key, oid);
          }
        }
      }
    } catch (Exception ex) {
      throw new RuntimeException("Could not run query for clasz " + clasz, ex);
    }
    logger.info("Checked " + count + " index nodes (offered " + offered + " OID's) for index " + clasz.getName() + "(" + field + ")");

    markEndOfQueue();
    return;
  }

  /**
   *
   */
  private void processIndexWithRange()
  {
    long oid;
    String key;
    String gln;
    bypass = true; // Do not evaluate again

    logger.info("Process indexWithRange class=" + clasz.getName() + " field=" + field + " range=" + range);

    // Index name
    String classGlobalNameIDX = GlobalName.Class2GlobalName(clasz) + "I";
    gln = GlobalName.buildGlobalName(classGlobalNameIDX, field, IndexUtils.normalizeIndexKey(range.getFrom()));

    int count = 0;
    try {
      while ((key = gtm.ORDER(gln)) != null) {
        // No more items?
        if (key == null)
          break;

        boolean addItem = OPImpl.eval(range, key);
        if (!addItem)
          break;

        count++;
        gln = GlobalName.buildGlobalName(classGlobalNameIDX, field, key);

        String oidKey = GlobalName.buildGlobalName(classGlobalNameIDX, field, key, -1);
        while ((oidKey = gtm.ORDER(oidKey)) != null) {
          oid = Long.parseLong(oidKey);
          offer(oid);
          oidKey = GlobalName.buildGlobalName(classGlobalNameIDX, field, key, oid);
        }
      }
    } catch (Exception ex) {
      throw new RuntimeException("Could not run query for clasz " + clasz, ex);
    }
    logger.info("Checked " + count + " index nodes (offered " + offered + " OID's) for index " + clasz.getName() + "(" + field + ")");

    markEndOfQueue();
    return;
  }

  private void processINQueue()
  {
    logger.info("process INQueue");

    int cycles = MAX_POLL_CYCLES;

    while (true) {
      Long oid = queueIN.poll();
      if (oid != null) {
        if (oid.equals(GTM.END_OF_QUEUE)) {
          break;
        } else {
          polled++;
          offer(oid);
          cycles = MAX_POLL_CYCLES;
        }
      } else {
        cycles--;
        if (cycles <= 0)
          throw new RuntimeException("Could not receive objects from queue. Timeout!");
        GTMUtils.sleep(25);
      }
    }

    markEndOfQueue();
  }

  /**
   *
   */
  private void fullTableScan()
  {
    logger.info("fullTableScan");

    long oid = -1;

    try {
      while (oid != GTM.END_OF_QUEUE) {
        // Get the ID level
        String key = GlobalName.buildGlobalName(clasz, oid);
        String order = gtm.ORDER(key);

        // No more items?
        if (order == null) {
          break;
        } else {
          // Add to queue
          oid = Long.parseLong(order);
          offer(oid);
        }
      }

    } catch (Exception ex) {
      throw new RuntimeException("Could not run query for clasz " + clasz, ex);
    }

    // Mark end of queue
    markEndOfQueue();
  }

  /**
   *
   * @param oid
   */
  private void offer(Long oid)
  {
    if (evaluate(oid)) {
      while (!queueOUT.offer(oid))
        GTMUtils.sleep(10);

      offered++;

      if (!notified)
        notifyQueue();
    }
  }

  /**
   *
   * @param oid
   * @return
   */
  protected boolean evaluate(long oid)
  {
    if (predicate != null) {
      return predicate.match(session.getByID(clasz, oid));

    } else {
      if (bypass || operator == null)
        return true;

      String globalName = GlobalName.buildGlobalName(clasz, oid, field);
      String globalValue = gtm.GET(globalName);
      if (globalValue == null)
        return false;

      if (function != null)
        globalValue = FUNCTIONImpl.eval(function, globalValue);

      if (operator == OP.RANGE) {
        return OPImpl.eval(range, globalValue);
      } else {
        return OPImpl.eval(operator, globalValue, value);
      }
    }
  }

  /**
   *
   */
  protected void notifyQueue()
  {
    if (!notified) {
      synchronized (queueOUT) {
        queueOUT.notify();
      }
      notified = true;
    }
  }

  /**
   *
   */
  private void markEndOfQueue()
  {
    queueOUT.offer(GTM.END_OF_QUEUE);
    completed = true;
  }

  public void sort()
  {
    this.sort = SORT.ASCENDING;
  }

  public void sortDescending()
  {
    this.sort = SORT.DESCENDING;
  }

  public Comparator getComparator()
  {
    return comparator;
  }

  public Class<?> getClasz()
  {
    return clasz;
  }

  public AbstractQueue<Long> getQueueOUT()
  {
    return queueOUT;
  }

  public void setQueueOUT(AbstractQueue<Long> queueOUT)
  {
    this.queueOUT = queueOUT;
  }

  /**
   *
   * @return
   */
  public boolean isCompleted()
  {
    return completed;
  }

  public void waitForCompleted()
  {
    while (!completed) {
      GTMUtils.sleep(25);
    }
  }

  @Override
  public String toString()
  {
    StringBuilder sb = new StringBuilder();
    sb.append("class=" + clasz.getName());
    if (field != null) {
      sb.append(", field=" + field);
      sb.append(", op=" + operator);
      sb.append(", func=" + function);
      sb.append(", value=" + value);
    }
    if (predicate != null) {
      sb.append(", predicate=" + predicate);
    }
    sb.append(", bypass=" + bypass);
    sb.append("; polled=" + polled);
    sb.append(", offered=" + offered);
    sb.append(", notified=" + notified);
    sb.append(", completed=" + completed);
    return sb.toString();
  }
}
TOP

Related Classes of de.linwave.gtm.Constraint

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.