You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@rya.apache.org by pu...@apache.org on 2015/10/28 20:24:02 UTC

[08/51] [partial] incubator-rya git commit: now including the actual project

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/OGCFilter.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/OGCFilter.java b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/OGCFilter.java
new file mode 100644
index 0000000..7bf622d
--- /dev/null
+++ b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/OGCFilter.java
@@ -0,0 +1,241 @@
+package ss.cloudbase.core.iterators.filter.ogc;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import ss.cloudbase.core.iterators.filter.ogc.operation.IOperation;
+
+import cloudbase.core.data.Key;
+import cloudbase.core.data.Value;
+import cloudbase.core.iterators.filter.Filter;
+import cloudbase.start.classloader.CloudbaseClassLoader;
+
+/**
+ * The OGCFilter class provides a basic implementation of the 
+ * <a href="http://www.opengeospatial.org/standards/filter">OGC Filter Encoding specification</a>. 
+ * This allows for arbitrary queries to be passed via XML and executed in a distributed fashion across tablet servers. The following
+ * code sets up a basic FilteringIterator that uses this filter (note that this jar must be present in each
+ * of the tablet servers' classpaths to work):
+ * 
+ * <code>
+ * <pre>
+ * cloudbase.core.client.Scanner reader;
+ * // set up the reader ...
+ *  
+ * // we're going to parse a row formated like key:value|key:value|key:value and return all of the rows
+ * // where the key "city" starts with "new"
+ * String filter = "&lt;PropertyIsLike&gt;&lt;PropertyName&gt;city&lt;/PropertyName&gt;&lt;Literal&gt;new*&lt;/Literal&gt;&lt;/PropertyIsLike&gt;";
+ * 
+ * reader.setScanIterators(50, FilteringIterator.class.getName(), "myIterator");
+ * reader.setScanIteratorOption("myIterator", "0", OGCFilter.class.getName());
+ * reader.setScanIteratorOption("myIterator", "0." + OGCFilter.OPTION_PAIR_DELIMITER, "\\|");
+ * reader.setScanIteratorOption("myIterator", "0." + OGCFilter.OPTION_VALUE_DELIMITER, ":");
+ * reader.setScanIteratorOption("myIterator", "0." + OGCFilter.OPTION_FILTER, filter);
+ * <pre>
+ * </code>
+ *  
+ * @author William Wall
+ */
+public class OGCFilter implements Filter {
+	private static final Logger logger = Logger.getLogger(OGCFilter.class);
+	
+	/** The string that separates the key/value pairs in the row value. */
+	public static final String OPTION_PAIR_DELIMITER = "pairDelimiter";
+	
+	/** The string that separates the key and the value(s) within a pair in the row value. */
+	public static final String OPTION_VALUE_DELIMITER = "valueDelimiter";
+	
+	/** The OGC Filter Encoding XML as a string */
+	public static final String OPTION_FILTER = "filter";
+	
+	/** Specifies the column name for the column family. If this option is not included, the column family is not included in the row. */
+	public static final String OPTION_COLF_NAME = "colfName";
+	
+	/** Specifies the column name for the column qualifier. If this option is not included, the column qualifier is not included in the row. */
+	public static final String OPTION_COLQ_NAME = "colqName";
+	
+	/** Specifies the compare type for the filter. Defaults to "auto". **/
+	public static final String OPTION_COMPARE_TYPE = "compareType";
+	
+	public static final String TYPE_NUMERIC = "numeric";
+	
+	public static final String TYPE_STRING = "string";
+	
+	public static final String TYPE_AUTO = "auto";
+	
+	/** Contains the pair delimiter provided through the <code>OPTION_PAIR_DELIMITER</code> option. */
+	protected String pairDelimiter;
+	
+	/** Contains the value delimiter provided through the <code>OPTION_VALUE_DELIMITER</code> option. */
+	protected String valueDelimiter;
+	
+	/** Contains the column family column name provided through the <code>OPTION_COLF_NAME</code> option. */
+	protected String colfName;
+	
+	/** Contains the column qualifier column name provided through the <code>OPTION_COLQ_NAME</code> option. */
+	protected String colqName;
+	
+	/** The root operation of the query tree **/
+	protected IOperation root;
+	
+	/** The compare type for the query tree **/
+	protected String compareType;
+
+	/**
+	 * Whether or not to accept this key/value entry. A map of row keys and values is parsed and then sent off to the process function to be evaluated.
+	 * @param key The cloudbase entry key
+	 * @param value The cloudbase entry value
+	 * @return True if the entry should be included in the results, false otherwise
+	 */
+	@Override
+	public boolean accept(Key key, Value value) {
+		if (root != null) {
+			Map<String, String> row = getRow(key, value);
+			if (root != null) {
+				return root.execute(row);
+			}
+		}
+		return false;
+	}
+	
+	public boolean accept(Map<String, String> record) {
+		if (root != null) {
+			return root.execute(record);
+		}
+		return false;
+	}
+	
+	/**
+	 * Parses the cloudbase value into a map of key/value pairs. If the <code>OPTION_COLF_NAME</code> 
+	 * or <code>OPTION_COLQ_NAME</code> options were used, then they will also be added to the row map. 
+	 * By default, pairs are delimited by the first unicode character ("\u0000") and values by the last unicode
+	 * character ("\uFFFD"). See the <code>OPTION_PAIR_DELIMITER</code> and <code>OPTION_VALUE_DELIMITER</code> 
+	 * options to change these values.
+	 * 
+	 * @param cbKey The cloudbase entry key
+	 * @param cbValue The cloudbase entry value
+	 * @return A map that represents this row
+	 */
+	protected Map<String, String> getRow(Key cbKey, Value cbValue) {
+		//TODO: This should really be replaced by CBValueFormatter.parse(value.toString()), but I'm hesitant to require
+		// more jars (common-data and google-collections) to be in the cloudbase/lib directory. Also, what do we do with
+		// a field with multiple values? Should we just assume that if any value in that field matches then the row
+		// matches? Or should they all have to match? 
+		
+		String value = cbValue.toString();
+		Map<String, String> row = new HashMap<String, String>();
+		
+		if (colfName != null) {
+			row.put(colfName, cbKey.getColumnFamily().toString());
+		}
+		if (colqName != null) {
+			row.put(colqName, cbKey.getColumnQualifier().toString());
+		}
+		
+		// Determine the start/end of the value.
+		int valueStartIndex = 0;
+		int valueEndIndex = value.length();
+		
+		int vLen = valueDelimiter.length();
+		int fLen = pairDelimiter.length();
+
+		// Parse each of the values from the row value.
+		while (valueStartIndex < valueEndIndex) {
+			int vIndex = value.indexOf(valueDelimiter, valueStartIndex);
+	
+			// If an "equals" sign was found, parse the key and value.
+			if (vIndex != -1) {
+				String key = value.substring(valueStartIndex, vIndex).trim();
+				int v = value.indexOf(valueDelimiter, vIndex + vLen);
+				if (v == -1) {
+					v = valueEndIndex;
+				}
+				int f = value.indexOf(pairDelimiter, vIndex + vLen);
+				if (f == -1) {
+					f = valueEndIndex;
+				}
+				
+				int fIndex = Math.min(f,v);
+				String val = value.substring(vIndex + 1, fIndex).trim();
+				valueStartIndex = f;
+				valueStartIndex += fLen;
+				row.put(key, val);
+			}
+		}
+		
+		return row;
+	}
+
+	@Override
+	public void init(Map<String, String> options) {
+		pairDelimiter = options.get(OPTION_PAIR_DELIMITER);
+		if (pairDelimiter == null || pairDelimiter.length() == 0) {
+			pairDelimiter = "\u0000";
+		}
+		
+		valueDelimiter = options.get(OPTION_VALUE_DELIMITER);
+		if (valueDelimiter == null || valueDelimiter.length() == 0) {
+			valueDelimiter = "\uFFFD";
+		}
+		
+		compareType = options.get(OPTION_COMPARE_TYPE);
+		if (compareType == null || compareType.length() == 0) {
+			compareType = TYPE_AUTO;
+		}
+		
+		colfName = options.get(OPTION_COLF_NAME);
+		colqName = options.get(OPTION_COLQ_NAME);
+		
+		try {
+			DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+			InputSource is = new InputSource();
+			is.setCharacterStream(new StringReader(options.get(OPTION_FILTER)));
+			Document doc = builder.parse(is);
+			Node filter = doc.getDocumentElement();
+			if (filter.getNodeName().equalsIgnoreCase("filter")) {
+				filter = filter.getFirstChild();
+			}
+			root = createOperationTree(filter);
+		} catch (IOException e) {
+			logger.error(e,e);
+		} catch (SAXException e) {
+			logger.error(e,e);
+		} catch (ParserConfigurationException e) {
+			logger.error(e,e);
+		}
+	}
+	
+	/**
+	 * Creates the operation tree from the filter XML
+	 * @param node The filter XML node to parse
+	 * @return The root IOperation
+	 */
+	protected IOperation createOperationTree(Node node) {
+		try {
+			// instantiate the operation and initialize it
+			Class<? extends IOperation> clazz = CloudbaseClassLoader.loadClass(IOperation.class.getPackage().getName() + "." + node.getNodeName(), IOperation.class);
+			IOperation op = clazz.newInstance();
+			op.init(node, compareType);
+			return op;
+		} catch (ClassNotFoundException e) {
+			logger.warn("Operation not supported: " + node.getNodeName());
+		} catch (InstantiationException e) {
+			logger.error(e,e);
+		} catch (IllegalAccessException e) {
+			logger.error(e,e);
+		}
+		return null;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/AbstractComparisonOp.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/AbstractComparisonOp.java b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/AbstractComparisonOp.java
new file mode 100644
index 0000000..46b1cf9
--- /dev/null
+++ b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/AbstractComparisonOp.java
@@ -0,0 +1,80 @@
+package ss.cloudbase.core.iterators.filter.ogc.operation;
+
+import java.util.List;
+import java.util.Map;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import ss.cloudbase.core.iterators.filter.ogc.OGCFilter;
+
+
+
+/**
+ * This class provides a simple init method for setting up most of the variables
+ * needed to do a comparison operation between two values.
+ * 
+ * @author William Wall
+ */
+public abstract class AbstractComparisonOp {
+	protected String name, literal, value;
+	protected boolean isNumeric = false;
+	protected double literalNum, valueNum;
+	protected String compareType;
+	
+	public void init(Node node, String compareType) {
+		this.compareType = compareType;
+		Node child;
+		NodeList children = node.getChildNodes();
+		for (int i = 0; i < children.getLength(); i++) {
+			child = children.item(i);
+			if (child.getNodeName().equalsIgnoreCase("PropertyName")) {
+				name = child.getTextContent();
+			} else {
+				literal = child.getTextContent();
+			}
+		}
+		
+		if (compareType.equalsIgnoreCase(OGCFilter.TYPE_NUMERIC) || compareType.equalsIgnoreCase(OGCFilter.TYPE_AUTO)) {
+			literalNum = parseNumeric(literal);
+			isNumeric = !Double.isNaN(literalNum);
+		}
+	}
+	
+	public List<IOperation> getChildren() {
+		return null;
+	}
+	
+	protected boolean checkRowNumeric(String s) {
+		if (isNumeric) {
+			valueNum = parseNumeric(s);
+			return valueNum != Double.NaN;
+		}
+		return false;
+	}
+	
+	public String getValue(Map<String, String> row) {
+		String value = row.get(name);
+		
+		// nulls will be lexicographically equal to ""
+		if (value == null) {
+			value = "";
+		}
+		return value;
+	}
+	
+	public static double parseNumeric(String s) {
+		// see if the string can be parsed as a double or an integer
+		double val = Double.NaN;
+		try {
+			val = Double.parseDouble(s);
+		} catch (Exception e) {
+			try {
+				val = new Double(Integer.parseInt(s));
+			} catch (Exception e2) {
+				
+			}
+		}
+		return val;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/AbstractLogicalOp.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/AbstractLogicalOp.java b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/AbstractLogicalOp.java
new file mode 100644
index 0000000..0400f61
--- /dev/null
+++ b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/AbstractLogicalOp.java
@@ -0,0 +1,40 @@
+package ss.cloudbase.core.iterators.filter.ogc.operation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import cloudbase.start.classloader.CloudbaseClassLoader;
+
+public class AbstractLogicalOp {
+	private static final Logger logger = Logger.getLogger(AbstractLogicalOp.class);
+	
+	List<IOperation> children = new ArrayList<IOperation>();
+	
+	public void init(Node node, String compareType) {
+		Node child;
+		NodeList children = node.getChildNodes();
+		for (int i = 0; i < children.getLength(); i++) {
+			child = children.item(i); 
+			try {
+				Class<? extends IOperation> clazz = CloudbaseClassLoader.loadClass(IOperation.class.getPackage().getName() + "." + child.getNodeName(), IOperation.class);
+				IOperation op = clazz.newInstance();
+				op.init(child, compareType);
+				this.children.add(op);
+			} catch (ClassNotFoundException e) {
+				logger.warn("Operation not supported: " + node.getNodeName());
+			} catch (InstantiationException e) {
+				logger.error(e,e);
+			} catch (IllegalAccessException e) {
+				logger.error(e,e);
+			}
+		}
+	}
+	
+	public List<IOperation> getChildren() {
+		return children;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/And.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/And.java b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/And.java
new file mode 100644
index 0000000..b192b19
--- /dev/null
+++ b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/And.java
@@ -0,0 +1,29 @@
+package ss.cloudbase.core.iterators.filter.ogc.operation;
+
+import java.util.Map;
+
+/**
+ * Executes a logical AND on all the child operations.
+ * 
+ * <code>
+ * <pre>
+ * &lt;And&gt;
+ * 	&lt;PropertyIsEqualTo&gt;...
+ * 	&lt;PropertyIsLessThan&gt;...
+ * &lt;/And&gt;
+ * </pre>
+ * </code>
+ * 
+ * @author William Wall
+ */
+public class And extends AbstractLogicalOp implements IOperation {
+	@Override
+	public boolean execute(Map<String, String> row) {
+		boolean result = true;
+		for (int i = 0; i < children.size(); i++) {
+			result = children.get(i).execute(row);
+			if (!result) break;
+		}
+		return result;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/BBOX.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/BBOX.java b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/BBOX.java
new file mode 100644
index 0000000..8596338
--- /dev/null
+++ b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/BBOX.java
@@ -0,0 +1,125 @@
+package ss.cloudbase.core.iterators.filter.ogc.operation;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.Point2D;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+
+/**
+ * Tests a row to see if it falls within the given shape. The shape should be
+ * defined in degrees. There is no need to send a property name since all the
+ * rows contain either lonself/latself or lon/lat fields.
+ * 
+ * Example:
+ * <pre>
+ * 	&lt;BBOX&gt;
+ * 		&lt;gml:Envelope&gt;
+ * 			&lt!-- coordinates are in lon/lat order --&gt;
+ * 			&lt;gml:LowerCorner&gt;13.09 31.5899&lt;/gml:LowerCorner&gt;
+ * 			&lt;gml:UpperCorner&gt;35.725 42.8153&lt;/gml:UpperCorner&gt;
+ * 		&lt;/gml:Envelope&gt;
+ * 	&lt;/BBOX&gt;
+ * </pre>
+ * 
+ * @author William Wall
+ */
+public class BBOX implements IOperation {
+	private static final Logger logger = Logger.getLogger(BBOX.class);
+	
+	Shape shape;
+	
+	// longitude column names in order of priority
+	protected static final String[] LON_NAMES = {
+		"lonself",
+		"lon",
+		"long",
+		"longitude"
+	};
+	
+	// latitude column names in order of priority
+	protected static final String[] LAT_NAMES = {
+		"latself",
+		"lat",
+		"latitude"
+	};
+	
+	@Override
+	public boolean execute(Map<String, String> row) {
+		Point2D p = BBOX.getPoint(row);
+		
+		if (p != null && shape != null) {
+			if (shape.contains(p)) {
+				return true;
+			} else {
+				// attempt to normalize the point into the shape in the event that the shape
+				// bounds are outside of -180 to 180
+				Rectangle bounds = shape.getBounds();
+				while (p.getX() < bounds.getMinX()) {
+					p.setLocation(p.getX() + 360, p.getY());
+				}
+				while (p.getX() > bounds.getMaxX()) {
+					p.setLocation(p.getX() - 360, p.getY());
+				}
+				
+				return shape.contains(p);
+			}
+		}
+		
+		return false;
+	}
+
+	@Override
+	public List<IOperation> getChildren() {
+		return null;
+	}
+
+	@Override
+	public void init(Node node, String compareType) {
+		NodeList children = node.getChildNodes();
+		for (int i = 0; i < children.getLength(); i++) {
+			shape = ShapeFactory.getShape(children.item(i));
+			if (shape != null) {
+				break;
+			}
+		}
+		
+	}
+	
+	/**
+	 * Gets a point that represents the location of this row. See 
+	 * @param row
+	 * @return The point object as (x - Longitude, y - Latitude)
+	 */
+	protected static Point2D getPoint(Map<String, String> row) {
+		Point2D.Double p = new Point2D.Double();
+		p.x = getDegree(row, LON_NAMES);
+		p.y = getDegree(row, LAT_NAMES);
+		return p;
+	}
+	
+	protected static double getDegree(Map<String, String> row, String[] cols) {
+		double num = Double.NaN;
+		String value;
+		for (int i = 0; i < cols.length; i++) {
+			if (row.containsKey(cols[i])) {
+				value = row.get(cols[i]);
+				if (value != null && !value.equals("-")) {
+					try {
+						num = Double.parseDouble(value);
+						break;
+					} catch (NumberFormatException e) {
+						logger.warn("Could not parse degree value from " + cols[i] + " = " + value);
+					}
+				}
+			}
+		}
+		
+		return num;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/IOperation.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/IOperation.java b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/IOperation.java
new file mode 100644
index 0000000..6ad8ebe
--- /dev/null
+++ b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/IOperation.java
@@ -0,0 +1,30 @@
+package ss.cloudbase.core.iterators.filter.ogc.operation;
+
+import java.util.List;
+import java.util.Map;
+
+import org.w3c.dom.Node;
+
+public interface IOperation {
+	
+	/**
+	 * Sets up the operation from the filter XML node
+	 * @param node The node
+	 * @param compareType The compare type. Defaults to "auto", but you can force it to be "numeric" or "string".
+	 */
+	public void init(Node node, String compareType);
+	
+	/**
+	 * Executes the operation indicated by the given node in the query
+	 * tree.
+	 * @param row The key/value pairs for the current row
+	 * @return The boolean evaluation of the operation
+	 */
+	public boolean execute(Map<String, String> row);
+	
+	/**
+	 * Returns the nodes children. This is only applicable to logical
+	 * operations (AND, OR, NOT).
+	 */
+	public List<IOperation> getChildren();
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/Not.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/Not.java b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/Not.java
new file mode 100644
index 0000000..74826a8
--- /dev/null
+++ b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/Not.java
@@ -0,0 +1,35 @@
+package ss.cloudbase.core.iterators.filter.ogc.operation;
+
+import java.util.Map;
+
+/**
+ * Executes a logical NOT on the child operations. If there is a single child, then 
+ * the operation is NOT. If more than one child exists, this operation defaults to
+ * NOR behavior. For NAND behavior, make a single AND child of NOT.
+ * 
+ * <code>
+ * <pre>
+ * &lt;Not&gt;
+ * 	&lt;PropertyIsEqualTo&gt;...
+ * &lt;/Not&gt;
+ * </pre>
+ * </code>
+ * 
+ * @author William Wall
+ *
+ */
+public class Not extends AbstractLogicalOp implements IOperation {
+
+	@Override
+	public boolean execute(Map<String, String> row) {
+		// For typical NOT behavior, a NOT group should have one child. If it has more than one child, it behaves
+		// like NOR. NAND/NOR behavior can be implemented by giving the Not group a child group of AND/OR.
+		boolean result = true;
+		for (int i = 0; i < children.size(); i++) {
+			result = !children.get(i).execute(row);
+			// in the case that there are multiple children, treat them as NOR
+			if (!result) break;
+		}
+		return result;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/Or.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/Or.java b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/Or.java
new file mode 100644
index 0000000..0a3dd6e
--- /dev/null
+++ b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/Or.java
@@ -0,0 +1,29 @@
+package ss.cloudbase.core.iterators.filter.ogc.operation;
+
+import java.util.Map;
+
+/**
+ * Executes a logical OR on the child operations.
+ * 
+ * <code>
+ * <pre>
+ * &lt;Or&gt;
+ * 	&lt;PropertyIsEqualTo&gt;...
+ * 	&lt;PropertyIsLessThan&gt;...
+ * &lt;/Or&gt;
+ * </pre>
+ * </code>
+ * 
+ * @author William Wall
+ */
+public class Or extends AbstractLogicalOp implements IOperation {
+	@Override
+	public boolean execute(Map<String, String> row) {
+		boolean result = false;
+		for (int i = 0; i < children.size(); i++) {
+			result = children.get(i).execute(row);
+			if (result) break;
+		}
+		return result;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsBetween.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsBetween.java b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsBetween.java
new file mode 100644
index 0000000..2c9d86c
--- /dev/null
+++ b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsBetween.java
@@ -0,0 +1,76 @@
+package ss.cloudbase.core.iterators.filter.ogc.operation;
+
+import java.util.List;
+import java.util.Map;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import ss.cloudbase.core.iterators.filter.ogc.OGCFilter;
+
+
+/**
+ * An operation that determines if the row's value is between the given
+ * boundary values.
+ * 
+ * Example:
+ * <pre>
+ * 	&lt;PropertyIsBetween&gt;
+ * 		&lt;PropertyName&gt;height&lt;/PropertyName&gt;
+ * 		&lt;LowerBoundary&gt;&lt;Literal&gt;180&lt;/Literal&gt;&lt;/LowerBoundary&gt;
+ * 		&lt;UpperBoundary&gt;&lt;Literal&gt;200&lt;/Literal&gt;&lt;/UpperBoundary&gt;
+ * 	&lt;/PropertyIsBetween&gt;
+ * </pre>
+ * 
+ * @author William Wall
+ */
+public class PropertyIsBetween implements IOperation {
+	String name;
+	String lower, upper, value;
+	double lowerNum, upperNum, valueNum;
+	boolean isNumeric = false;
+	
+	@Override
+	public boolean execute(Map<String, String> row) {
+		if (isNumeric) {
+			valueNum = AbstractComparisonOp.parseNumeric(row.get(name));
+			if (valueNum != Double.NaN) {
+				return lowerNum <= valueNum && valueNum <= upperNum;
+			}
+		}
+		
+		value = row.get(name);
+		if (value == null) {
+			value = "";
+		}
+		
+		return value.compareTo(lower) > -1 && value.compareTo(upper) < 1;
+	}
+
+	@Override
+	public List<IOperation> getChildren() {
+		return null;
+	}
+
+	@Override
+	public void init(Node node, String compareType) {
+		Node child;
+		NodeList children = node.getChildNodes();
+		for (int i = 0; i < children.getLength(); i++) {
+			child = children.item(i);
+			if (child.getNodeName().equalsIgnoreCase("PropertyName")) {
+				name = child.getTextContent();
+			} else if (child.getNodeName().equalsIgnoreCase("LowerBoundary")) {
+				lower = child.getTextContent();
+			} else if (child.getNodeName().equalsIgnoreCase("UpperBoundary")) {
+				upper = child.getTextContent();
+			}
+		}
+		
+		if (compareType.equalsIgnoreCase(OGCFilter.TYPE_NUMERIC) || compareType.equalsIgnoreCase(OGCFilter.TYPE_AUTO)) {
+			upperNum = AbstractComparisonOp.parseNumeric(upper);
+			lowerNum = AbstractComparisonOp.parseNumeric(lower);
+			isNumeric = !Double.isNaN(upperNum) && !Double.isNaN(lowerNum);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsEqualTo.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsEqualTo.java b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsEqualTo.java
new file mode 100644
index 0000000..93fa3f5
--- /dev/null
+++ b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsEqualTo.java
@@ -0,0 +1,30 @@
+package ss.cloudbase.core.iterators.filter.ogc.operation;
+
+import java.util.Map;
+
+/**
+ * An operation to see whether the values are equal or not.
+ * 
+ * Example:
+ * <pre>
+ * 	&lt;PropertyIsEqualTo&gt;
+ * 		&lt;PropertyName&gt;user&lt;/PropertyIsEqualTo&gt;
+ * 		&lt;Literal&gt;CmdrTaco&lt;/Literal&gt;
+ *  &lt;/PropertyIsEqualTo&gt;
+ * </pre>
+ * 
+ * @author William Wall
+ */
+public class PropertyIsEqualTo extends AbstractComparisonOp implements IOperation {
+
+	@Override
+	public boolean execute(Map<String, String> row) {
+		value = getValue(row);
+		
+		if (checkRowNumeric(value)) {
+			return valueNum == literalNum;
+		}
+		
+		return value.equals(literal);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsGreaterThan.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsGreaterThan.java b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsGreaterThan.java
new file mode 100644
index 0000000..8eb9ec0
--- /dev/null
+++ b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsGreaterThan.java
@@ -0,0 +1,29 @@
+package ss.cloudbase.core.iterators.filter.ogc.operation;
+
+import java.util.Map;
+
+/**
+ * An operation to see if the row value is greater than the given value.
+ * 
+ * Example:
+ * <pre>
+ * 	&lt;PropertyIsGreaterThan&gt;
+ * 		&lt;PropertyName&gt;height&lt;/PropertyName&gt;
+ * 		&lt;Literal&gt;200&lt;/Literal&gt;
+ *	&lt;/PropertyIsGreaterThan&gt;
+ * </pre>
+ * @author William Wall
+ */
+public class PropertyIsGreaterThan extends AbstractComparisonOp implements IOperation {
+
+	@Override
+	public boolean execute(Map<String, String> row) {
+		value = getValue(row);
+		
+		if (checkRowNumeric(value)) {
+			return valueNum > literalNum;
+		}
+		
+		return value.compareTo(literal) > 0;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsGreaterThanOrEqualTo.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsGreaterThanOrEqualTo.java b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsGreaterThanOrEqualTo.java
new file mode 100644
index 0000000..17fb1dc
--- /dev/null
+++ b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsGreaterThanOrEqualTo.java
@@ -0,0 +1,29 @@
+package ss.cloudbase.core.iterators.filter.ogc.operation;
+
+import java.util.Map;
+
+/**
+ * An operation to see if the row value is greater than or equal to the given value.
+ * 
+ * Example:
+ * 	<pre>
+ * 	&lt;PropertyIsGreaterThanOrEqualTo&gt;
+ * 		&lt;PropertyName&gt;height&lt;/PropertyName&gt;
+ * 		&lt;Literal&gt;100&lt;/Literal&gt;
+ * 	&lt;/PropertyIsGreaterThanOrEqualTo&gt;
+ * 	</pre>
+ * @author William Wall
+ */
+public class PropertyIsGreaterThanOrEqualTo extends AbstractComparisonOp implements IOperation {
+
+	@Override
+	public boolean execute(Map<String, String> row) {
+		value = getValue(row);
+		
+		if (checkRowNumeric(value)) {
+			return valueNum >= literalNum;
+		}
+		
+		return value.compareTo(literal) > -1;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsLessThan.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsLessThan.java b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsLessThan.java
new file mode 100644
index 0000000..f094c99
--- /dev/null
+++ b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsLessThan.java
@@ -0,0 +1,31 @@
+package ss.cloudbase.core.iterators.filter.ogc.operation;
+
+import java.util.Map;
+
+/**
+ * An operation to see if the row value is less than the given value.
+ * 
+ * Example:
+ * <pre>
+ * 	&lt;PropertyIsLessThan&gt;
+ * 		&lt;PropertyName&gt;height&lt;/PropertyName&gt;
+ * 		&lt;Literal&gt;180&lt;/Literal&gt;
+ *	&lt;/PropertyIsLessThan&gt;
+ * </pre>
+ * 
+ * @author William Wall
+ */
+public class PropertyIsLessThan extends AbstractComparisonOp implements IOperation {
+
+	@Override
+	public boolean execute(Map<String, String> row) {
+		value = getValue(row);
+		
+		if (checkRowNumeric(value)) {
+			return valueNum < literalNum;
+		}
+		
+		return value.compareTo(literal) < 0;
+	}
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsLessThanOrEqualTo.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsLessThanOrEqualTo.java b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsLessThanOrEqualTo.java
new file mode 100644
index 0000000..9b01aae
--- /dev/null
+++ b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsLessThanOrEqualTo.java
@@ -0,0 +1,29 @@
+package ss.cloudbase.core.iterators.filter.ogc.operation;
+
+import java.util.Map;
+
+/**
+ * An operation to see if the row value is less than or equal to the given value.
+ * 
+ * <pre>
+ * 	&lt;PropertyIsLessThanOrEqualTo&gt;
+ * 		&lt;PropertyName&gt;height&lt;/PropertyName&gt;
+ * 		&lt;Literal&gt;100&lt;/Literal&gt;
+ * 	&lt;/PropertyIsLessThanOrEqualTo&gt;
+ * </pre>
+ * 
+ * @author William Wall
+ */
+public class PropertyIsLessThanOrEqualTo extends AbstractComparisonOp implements IOperation {
+
+	@Override
+	public boolean execute(Map<String, String> row) {
+		value = getValue(row);
+		
+		if (checkRowNumeric(value)) {
+			return valueNum <= literalNum;
+		}
+		
+		return value.compareTo(literal) < 1;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsLike.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsLike.java b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsLike.java
new file mode 100644
index 0000000..ad38951
--- /dev/null
+++ b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsLike.java
@@ -0,0 +1,144 @@
+package ss.cloudbase.core.iterators.filter.ogc.operation;
+
+import java.util.List;
+import java.util.Map;
+
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * An operation that determines if the row value is like the given value. This
+ * operation supports wildcards (*).
+ * 
+ * Example:
+ * 
+ * <pre>
+ * 	&lt;PropertyIsLike&gt;
+ * 		&lt;PropertyName&gt;city&lt;/PropertyName&gt;
+ * 		&lt;Literal&gt;new*&lt;/Literal&gt;
+ * 	&lt;/PropertyIsLike&gt;
+ * </pre>
+ * 
+ * @author William Wall
+ * 
+ */
+public class PropertyIsLike implements IOperation {
+	String pattern;
+	String name;
+
+	@Override
+	public boolean execute(Map<String, String> row) {
+		String value = row.get(name);
+		if (value == null) {
+			value = "";
+		}
+
+		return value.matches(pattern);
+	}
+
+	@Override
+	public List<IOperation> getChildren() {
+		return null;
+	}
+
+	@Override
+	public void init(Node node, String compareType) {
+		Node child;
+		NodeList children = node.getChildNodes();
+		for (int i = 0; i < children.getLength(); i++) {
+			child = children.item(i);
+			if (child.getNodeName().equalsIgnoreCase("PropertyName")) {
+				name = child.getTextContent();
+			} else {
+				pattern = child.getTextContent();
+			}
+		}
+
+		pattern = convertToRegex(node, pattern);
+	}
+
+	/**
+	 * Converts the pattern, wild card, single and escape characters to the
+	 * regular expression equivalents. Everything else in the pattern is treated
+	 * as a regex literal.
+	 * 
+	 * @param node The PropertyIsLike node
+	 * @param likePattern The initial like pattern 
+	 * 
+	 * @return the equivalent regular expression string.
+	 */
+	public String convertToRegex(Node node, String likePattern) {
+		// Convert the pattern to a regular expression.
+		StringBuilder regex = new StringBuilder();
+		
+		NamedNodeMap attr = node.getAttributes();
+		
+		String wildCard = "*";
+		if (attr.getNamedItem("wildCard") != null) {
+			wildCard = attr.getNamedItem("wildCard").toString();
+		}
+		
+		String escapeChar = "\\";
+		if (attr.getNamedItem("escapeChar") != null) {
+			 escapeChar = attr.getNamedItem("escapeChar").toString();
+		}
+		
+		String singleChar = ".";
+		if (attr.getNamedItem("singleChar") != null) {
+			singleChar = attr.getNamedItem("singleChar").toString();
+		}
+		
+		int escapeCharIndex = likePattern.indexOf(escapeChar);
+
+		// These are required in WFS but we'll handle null values here.
+		int wildCardIndex = wildCard == null ? -1 : likePattern.indexOf(wildCard);
+		int singleCharIndex = singleChar == null ? -1 : likePattern.indexOf(singleChar);
+		for (int index = 0; index < likePattern.length(); index++) {
+			char ch = likePattern.charAt(index);
+			if (index == escapeCharIndex) {
+				escapeCharIndex = likePattern.indexOf(escapeChar, escapeCharIndex + escapeChar.length());
+
+				// If there are consecutive escape characters, skip to the
+				// next one to save it in the regex.
+				if (index + 1 == escapeCharIndex) {
+					escapeCharIndex = likePattern.indexOf(escapeChar, escapeCharIndex + escapeChar.length());
+				} else if (index + 1 == wildCardIndex) {
+					wildCardIndex = likePattern.indexOf(wildCard, wildCardIndex + wildCard.length());
+				} else if (index + 1 == singleCharIndex) {
+					singleCharIndex = likePattern.indexOf(singleChar, singleCharIndex + singleChar.length());
+				} else {
+					// This is an undefined condition, just skip the escape
+					// character.
+				}
+			}
+
+			// Insert the regular expression equivalent of a wild card.
+			else if (index == wildCardIndex) {
+				regex.append(".*");
+				index += wildCard.length() - 1;
+				wildCardIndex = likePattern.indexOf(wildCard, wildCardIndex + wildCard.length());
+			}
+
+			// Insert the regular expression equivalent of the single char.
+			else if (index == singleCharIndex) {
+				regex.append(".");
+				index += singleChar.length() - 1;
+				singleCharIndex = likePattern.indexOf(singleChar, singleCharIndex + singleChar.length());
+			}
+
+			// Handle certain characters in a special manner.
+			else if (('[' == ch) || (']' == ch) || ('\\' == ch) || ('^' == ch)) {
+				regex.append('\\').append(ch);
+			}
+
+			// Force everything else to be literals.
+			else {
+				regex.append('[').append(ch).append(']');
+			}
+		}
+		
+		// add case insensitive flag and start match at beginning of the string
+		return "(?i)^" + regex.toString();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsNotEqualTo.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsNotEqualTo.java b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsNotEqualTo.java
new file mode 100644
index 0000000..b62e6c6
--- /dev/null
+++ b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsNotEqualTo.java
@@ -0,0 +1,30 @@
+package ss.cloudbase.core.iterators.filter.ogc.operation;
+
+import java.util.Map;
+
+/**
+ * An operation that determines if the row value is not equal to the given value.
+ * 
+ * Example:
+ * <pre>
+ * 	&lt;PropertyIsNotEqualTo&gt;
+ * 		&lt;PropertyName&gt;weather&lt;/PropertyName&gt;
+ * 		&lt;Literal&gt;rainy&lt;/Literal&gt;
+ * 	&lt;/PropertyIsNotEqualTo&gt;
+ * </pre>
+ * 
+ * @author William Wall
+ *
+ */
+public class PropertyIsNotEqualTo extends AbstractComparisonOp implements IOperation {
+	@Override
+	public boolean execute(Map<String, String> row) {
+		value = getValue(row);
+		
+		if (checkRowNumeric(value)) {
+			return valueNum != literalNum;
+		}
+		
+		return !value.equals(literal);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsNull.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsNull.java b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsNull.java
new file mode 100644
index 0000000..d5d67c2
--- /dev/null
+++ b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/PropertyIsNull.java
@@ -0,0 +1,38 @@
+package ss.cloudbase.core.iterators.filter.ogc.operation;
+
+import java.util.List;
+import java.util.Map;
+
+import org.w3c.dom.Node;
+
+/**
+ * An operation to determine if the row value is null. Nulls and empty strings will both match.
+ *
+ * Example:
+ * <pre>
+ * 	&lt;PropertyIsNull&gt;
+ * 		&lt;PropertyName&gt;socialSkills&lt;/PropertyName&gt;
+ * 	&lt;/PropertyIsNull&gt;
+ * </pre>
+ * 
+ * @author William Wall
+ */
+public class PropertyIsNull implements IOperation {
+	String name;
+	
+	@Override
+	public boolean execute(Map<String, String> row) {
+		String value = row.get(name);
+		return value == null || value.length() == 0;
+	}
+
+	@Override
+	public List<IOperation> getChildren() {
+		return null;
+	}
+
+	@Override
+	public void init(Node node, String compareType) {
+		name = node.getTextContent();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/ShapeFactory.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/ShapeFactory.java b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/ShapeFactory.java
new file mode 100644
index 0000000..10fea78
--- /dev/null
+++ b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/operation/ShapeFactory.java
@@ -0,0 +1,133 @@
+package ss.cloudbase.core.iterators.filter.ogc.operation;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Path2D;
+import java.awt.geom.Point2D;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import ss.cloudbase.core.iterators.filter.ogc.util.GeoUtil;
+
+
+public class ShapeFactory {
+	private static final Logger logger = Logger.getLogger(ShapeFactory.class);
+	
+	public static Shape getShape(Node node) {
+		if (node.getNodeName().equalsIgnoreCase("gml:Envelope")) {
+			return parseEnvelope(node);
+		} else if (node.getNodeName().equalsIgnoreCase("gml:Polygon")) {
+			return parsePolygon(node);
+		} else if (node.getNodeName().equalsIgnoreCase("gml:CircleByCenterPoint")) {
+			return parseCircle(node);
+		}
+		
+		logger.warn("No parser implemented for: " + node.getLocalName());
+		return null;
+	}
+	
+	protected static Shape parseEnvelope(Node node) {
+		Rectangle rect = null;
+		
+		Node child;
+		NodeList children = node.getChildNodes();
+		for (int i = 0; i < children.getLength(); i++) {
+			child = children.item(i);
+			String[] parts = child.getTextContent().split("\\s");
+			
+			if (parts.length == 2) {
+				double lon = Double.parseDouble(parts[0]);
+				double lat = Double.parseDouble(parts[1]);
+				
+				if (rect == null) {
+					rect = new Rectangle();
+					rect.setFrame(lon, lat, 0, 0);
+				} else {
+					rect.add(lon, lat);
+				}
+			}
+		}
+
+		// If the rectangle width is greater than 180 degrees, the user most likely
+		// meant to use the inverse BBOX (where the east value is less than the west).
+		// This is for clients that wrap coordinates rather than use absolute coordinates.
+		if (rect.getWidth() > 180) {
+			rect.setFrame(rect.getMaxX(), rect.getMaxY(), 360 - rect.getWidth(), rect.getHeight());
+		}
+		
+		return rect;
+	}
+	
+	protected static Shape parsePolygon(Node node) {
+		Path2D poly = null;
+		
+		String text = node.getTextContent();
+		String[] list = text.split("\\s");
+		
+		for (int i = 1; i < list.length; i += 2) {
+			double lon = Double.parseDouble(list[i-1]);
+			double lat = Double.parseDouble(list[i]);
+			if (poly == null) {
+				poly = new Path2D.Double();
+				poly.moveTo(lon, lat);
+			} else {
+				poly.lineTo(lon, lat);
+			}
+		}
+		
+		return poly;
+	}
+	
+	protected static Shape parseCircle(Node node) {
+		Ellipse2D circle = null;
+		
+		double radius = Double.NaN, lon = Double.NaN, lat = Double.NaN;
+		String units = null;
+		
+		Node child;
+		NodeList children = node.getChildNodes();
+		try {
+			for (int i = 0; i < children.getLength(); i++) {
+				child = children.item(i);
+				if (child.getNodeName().equalsIgnoreCase("gml:radius")) {
+					radius = Double.parseDouble(child.getTextContent());
+					units = child.getAttributes().getNamedItem("uom").getTextContent();
+				} else {
+					String[] list = child.getTextContent().split("\\s");
+					lon = Double.parseDouble(list[0]);
+					lat = Double.parseDouble(list[1]);
+				}
+			}
+			
+			radius = convertToKM(radius, units);
+			Point2D center = new Point2D.Double(lon, lat);
+			Point2D end = GeoUtil.calculateEndLocation(center, radius, lat > 0 ? 180: 0);
+			
+			radius = Math.abs(end.getY() - lat);
+			circle = new Ellipse2D.Double();
+			circle.setFrameFromCenter(center, new Point2D.Double(center.getX() + radius, center.getY() + radius));
+		} catch (NumberFormatException e) {
+			
+		} catch (ArrayIndexOutOfBoundsException e) {
+			
+		}
+		
+		return circle;
+	}
+	
+	private static double convertToKM(double radius, String units) {
+		if (units.equalsIgnoreCase("km")) {
+			return radius;
+		} else if (units.equalsIgnoreCase("m")) {
+			return radius / 1000;
+		} else if (units.equalsIgnoreCase("mi")) {
+			return 0.621371192 * radius;
+		} else if (units.equalsIgnoreCase("ft")) {
+			return radius / 3280.8399;
+		}
+		return radius;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/util/GeoUtil.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/util/GeoUtil.java b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/util/GeoUtil.java
new file mode 100644
index 0000000..95259fa
--- /dev/null
+++ b/partition/common-query/src/main/java/ss/cloudbase/core/iterators/filter/ogc/util/GeoUtil.java
@@ -0,0 +1,32 @@
+package ss.cloudbase.core.iterators.filter.ogc.util;
+
+import java.awt.geom.Point2D;
+
+public class GeoUtil {
+	/**
+	 * Calculates an ending location from a point, distance, and bearing
+	 * @param point The start point
+	 * @param distance The distance from the start point in kilometers
+	 * @param bearing The bearing (in degrees) where north is 0
+	 * @return The resulting point
+	 */
+	public static Point2D calculateEndLocation(Point2D point, double distance, double bearing) {
+		double r = 6371; // earth's mean radius in km
+
+		double lon1 = Math.toRadians(point.getX());	
+		double lat1 = Math.toRadians(point.getY());
+		bearing = Math.toRadians(bearing);
+	
+		double lat2 = Math.asin( Math.sin(lat1) * Math.cos(distance/r) + Math.cos(lat1) * Math.sin(distance/r) * Math.cos(bearing) );
+		double lon2 = lon1 + Math.atan2(Math.sin(bearing) * Math.sin(distance/r) * Math.cos(lat1), Math.cos(distance/r) - Math.sin(lat1) * Math.sin(lat2));
+		
+		lon2 = (lon2+Math.PI)%(2*Math.PI) - Math.PI;  // normalise to -180...+180
+	
+		if (Double.isNaN(lat2) || Double.isNaN(lon2)) return null;
+	
+		lon2 = Math.toDegrees(lon2);
+		lat2 = Math.toDegrees(lat2);
+		
+		return new Point2D.Double(lon2, lat2);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/test/java/GVDateFilterTest.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/test/java/GVDateFilterTest.java b/partition/common-query/src/test/java/GVDateFilterTest.java
new file mode 100644
index 0000000..8ea5578
--- /dev/null
+++ b/partition/common-query/src/test/java/GVDateFilterTest.java
@@ -0,0 +1,156 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Map.Entry;
+
+import org.apache.hadoop.io.Text;
+import org.junit.Test;
+
+import ss.cloudbase.core.iterators.GMDenIntersectingIterator;
+import ss.cloudbase.core.iterators.filter.general.GVDateFilter;
+
+import cloudbase.core.client.Connector;
+import cloudbase.core.client.Scanner;
+import cloudbase.core.client.TableNotFoundException;
+import cloudbase.core.data.Key;
+import cloudbase.core.data.Range;
+import cloudbase.core.data.Value;
+import cloudbase.core.iterators.FilteringIterator;
+import cloudbase.core.security.Authorizations;
+
+/**
+ *
+ * @author rashah
+ */
+public class GVDateFilterTest
+{
+
+  private Connector cellLevelConn;
+  private Connector serializedConn;
+  private static final String TABLE = "partition";
+  private static final Authorizations AUTHS = new Authorizations("ALPHA,BETA,GAMMA".split(","));
+
+
+
+  protected Connector getSerializedConnector()
+  {
+    if (serializedConn == null)
+    {
+      serializedConn = SampleGVData.initConnector();
+      SampleGVData.writeDenSerialized(serializedConn, SampleGVData.sampleData());
+    }
+    return serializedConn;
+  }
+
+
+
+  protected Scanner getSerializedScanner()
+  {
+    Connector c = getSerializedConnector();
+    try
+    {
+      return c.createScanner(TABLE, AUTHS);
+    }
+    catch (TableNotFoundException e)
+    {
+      return null;
+    }
+  }
+
+  protected Scanner setUpGVDFFilter(Scanner s, String timesta)
+  {
+    try
+    {
+  
+      s.setScanIterators(50, FilteringIterator.class.getName(), "gvdf");
+      s.setScanIteratorOption("gvdf", "0", GVDateFilter.class.getName());
+      s.setScanIteratorOption("gvdf", "0." + GVDateFilter.OPTIONInTimestamp, timesta);
+
+    }
+    catch (IOException e)
+    {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
+    return s;
+  }
+
+  protected String checkSerialized(Scanner s)
+  {
+    StringBuilder sb = new StringBuilder();
+    boolean first = true;
+    for (Entry<Key, Value> e : s)
+    {
+
+      if (!first)
+      {
+        sb.append(",");
+      }
+      else
+      {
+        first = false;
+      }
+
+      String colq = e.getKey().getColumnQualifier().toString();
+
+      sb.append(colq);
+    }
+    return sb.toString();
+  }
+
+
+  @Test
+  public void testNoResults()
+  {
+
+    Scanner s = setUpGVDFFilter(getSerializedScanner(), "2008-03-03T20:44:28.633Z");
+    s.setRange(new Range());
+
+    assertTrue(checkSerialized(s).equals(""));
+  }
+
+
+  @Test
+  public void testOneResult()
+  {
+
+    Scanner s = setUpGVDFFilter(getSerializedScanner(), "2011-03-03T20:44:28.633Z");
+    s.setRange(new Range());
+
+    System.out.println(checkSerialized(s));
+
+    assertTrue(checkSerialized(s).equals("03"));
+  }
+
+  @Test
+  public void testTwoResults()
+  {
+
+    Scanner s = setUpGVDFFilter(getSerializedScanner(), "2009-03-03T20:44:28.633Z");
+    s.setRange(new Range());
+
+    assertTrue(checkSerialized(s).equals("04,01"));
+  }
+
+    @Test
+  public void testThreeResults()
+  {
+
+    Scanner s = setUpGVDFFilter(getSerializedScanner(), "2010-03-01T20:44:28.633Z");
+    s.setRange(new Range());
+
+    assertTrue(checkSerialized(s).equals("04,01,03"));
+  }
+
+  @Test
+  public void testDummyTest()
+  {
+    assertTrue(true);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/test/java/GVFrequencyFilterTest.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/test/java/GVFrequencyFilterTest.java b/partition/common-query/src/test/java/GVFrequencyFilterTest.java
new file mode 100644
index 0000000..25c602a
--- /dev/null
+++ b/partition/common-query/src/test/java/GVFrequencyFilterTest.java
@@ -0,0 +1,144 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Map.Entry;
+
+import org.apache.hadoop.io.Text;
+import org.junit.Test;
+
+import ss.cloudbase.core.iterators.GMDenIntersectingIterator;
+import ss.cloudbase.core.iterators.filter.general.GVFrequencyFilter;
+
+import cloudbase.core.client.Connector;
+import cloudbase.core.client.Scanner;
+import cloudbase.core.client.TableNotFoundException;
+import cloudbase.core.data.Key;
+import cloudbase.core.data.Range;
+import cloudbase.core.data.Value;
+import cloudbase.core.iterators.FilteringIterator;
+import cloudbase.core.security.Authorizations;
+
+/**
+ *
+ * @author rashah
+ */
+public class GVFrequencyFilterTest
+{
+
+  private Connector cellLevelConn;
+  private Connector serializedConn;
+  private static final String TABLE = "partition";
+  private static final Authorizations AUTHS = new Authorizations("ALPHA,BETA,GAMMA".split(","));
+
+
+
+  protected Connector getSerializedConnector()
+  {
+    if (serializedConn == null)
+    {
+      serializedConn = SampleGVData.initConnector();
+      SampleGVData.writeDenSerialized(serializedConn, SampleGVData.sampleData());
+    }
+    return serializedConn;
+  }
+
+
+
+  protected Scanner getSerializedScanner()
+  {
+    Connector c = getSerializedConnector();
+    try
+    {
+      return c.createScanner(TABLE, AUTHS);
+    }
+    catch (TableNotFoundException e)
+    {
+      return null;
+    }
+  }
+
+  protected Scanner setUpGVDFFilter(Scanner s, String Frequency)
+  {
+    try
+    {
+      s.clearScanIterators();
+  
+      s.setScanIterators(50, FilteringIterator.class.getName(), "gvff");
+      s.setScanIteratorOption("gvff", "0", GVFrequencyFilter.class.getName());
+      s.setScanIteratorOption("gvff", "0." + GVFrequencyFilter.OPTIONFrequency, Frequency);
+
+    }
+    catch (IOException e)
+    {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
+    return s;
+  }
+
+  protected String checkSerialized(Scanner s)
+  {
+    StringBuilder sb = new StringBuilder();
+    boolean first = true;
+    for (Entry<Key, Value> e : s)
+    {
+
+      if (!first)
+      {
+        sb.append(",");
+      }
+      else
+      {
+        first = false;
+      }
+
+      String colq = e.getKey().getColumnQualifier().toString();
+
+      //System.out.println(e.getKey()+"\t"+e.getValue());
+
+      sb.append(colq);
+    }
+    return sb.toString();
+  }
+
+  @Test
+  public void testNoMatch()
+  {
+
+    Scanner s = setUpGVDFFilter(getSerializedScanner(), "2000000000");
+    s.setRange(new Range());
+
+    assertTrue(checkSerialized(s).isEmpty());
+  }
+
+  @Test
+  public void testSingleMatch()
+  {
+    Scanner s = setUpGVDFFilter(getSerializedScanner(), "1500000000");
+    s.setRange(new Range());
+
+    assertTrue(checkSerialized(s).equals("01"));
+  }
+
+
+  @Test
+  public void testDoubleMatch()
+  {
+    Scanner s = setUpGVDFFilter(getSerializedScanner(), "1200000000");
+    s.setRange(new Range());
+
+    assertTrue(checkSerialized(s).equals("01,03"));
+  }
+
+  @Test
+  public void testDummyTest()
+  {
+    assertTrue(true);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/test/java/IteratorTest.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/test/java/IteratorTest.java b/partition/common-query/src/test/java/IteratorTest.java
new file mode 100644
index 0000000..1b5cf14
--- /dev/null
+++ b/partition/common-query/src/test/java/IteratorTest.java
@@ -0,0 +1,554 @@
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.hadoop.io.Text;
+import org.junit.Test;
+
+import ss.cloudbase.core.iterators.CellLevelFilteringIterator;
+import ss.cloudbase.core.iterators.CellLevelRecordIterator;
+import ss.cloudbase.core.iterators.ConversionIterator;
+import ss.cloudbase.core.iterators.GMDenIntersectingIterator;
+import ss.cloudbase.core.iterators.SortedMinIterator;
+import ss.cloudbase.core.iterators.SortedRangeIterator;
+import ss.cloudbase.core.iterators.UniqueIterator;
+import ss.cloudbase.core.iterators.filter.CBConverter;
+import cloudbase.core.client.Connector;
+import cloudbase.core.client.Scanner;
+import cloudbase.core.client.TableNotFoundException;
+import cloudbase.core.data.Key;
+import cloudbase.core.data.PartialKey;
+import cloudbase.core.data.Range;
+import cloudbase.core.data.Value;
+import cloudbase.core.security.Authorizations;
+
+public class IteratorTest {
+	private Connector cellLevelConn;
+	private Connector serializedConn;
+	
+	private static final String TABLE = "partition";
+	private static final Authorizations AUTHS = new Authorizations("ALPHA,BETA,GAMMA".split(","));
+	
+	public IteratorTest() {
+		
+	}
+	
+	protected Connector getCellLevelConnector() {
+		if (cellLevelConn == null) {
+			cellLevelConn = SampleData.initConnector();
+			SampleData.writeDenCellLevel(cellLevelConn, SampleData.sampleData());
+		}
+		return cellLevelConn;
+	}
+	
+	protected Connector getSerializedConnector() {
+		if (serializedConn == null) {
+			serializedConn = SampleData.initConnector();
+			SampleData.writeDenSerialized(serializedConn, SampleData.sampleData());
+			SampleData.writeDenProvenance(serializedConn);
+			SampleData.writeMinIndexes(serializedConn);
+		}
+		return serializedConn;
+	}
+	
+	protected Scanner getProvenanceScanner() {
+		Connector c = getSerializedConnector();
+		try {
+			return c.createScanner("provenance", AUTHS);
+		} catch (TableNotFoundException e) {
+			return null;
+		}
+	}
+	
+	protected Scanner getCellLevelScanner() {
+		Connector c = getCellLevelConnector();
+		try {
+			return c.createScanner(TABLE, AUTHS);
+		} catch (TableNotFoundException e) {
+			return null;
+		}
+	}
+	
+	protected Scanner getSerializedScanner() {
+		Connector c = getSerializedConnector();
+		try {
+			return c.createScanner(TABLE, AUTHS);
+		} catch (TableNotFoundException e) {
+			return null;
+		}
+	}
+	
+	protected Scanner setUpIntersectingIterator(Scanner s, Text[] terms, boolean multiDoc) {
+		try {
+			s.setScanIterators(50, GMDenIntersectingIterator.class.getName(), "ii");
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		s.setScanIteratorOption("ii", GMDenIntersectingIterator.indexFamilyOptionName, "index");
+		s.setScanIteratorOption("ii", GMDenIntersectingIterator.docFamilyOptionName, "event");
+		s.setScanIteratorOption("ii", GMDenIntersectingIterator.OPTION_MULTI_DOC, "" + multiDoc);
+		s.setScanIteratorOption("ii", GMDenIntersectingIterator.columnFamiliesOptionName, GMDenIntersectingIterator.encodeColumns(terms));
+		return s;
+	}
+	
+	protected String checkSerialized(Scanner s) {
+		StringBuilder sb = new StringBuilder();
+		boolean first = true;
+		for (Entry<Key, Value> e: s) {
+			if (!first) {
+				sb.append(",");
+			} else {
+				first = false;
+			}
+			
+			String colq = e.getKey().getColumnQualifier().toString();
+			
+			sb.append(colq);
+		}
+		return sb.toString();
+	}
+	
+	protected String checkCellLevel(Scanner s) {
+		StringBuilder sb = new StringBuilder();
+		boolean first = true;
+		for (Entry<Key, Value> e: s) {
+			String colq = e.getKey().getColumnQualifier().toString();
+			int i = colq.indexOf("\u0000");
+			if (i > -1) {
+				if (!first) {
+					sb.append(",");
+				} else {
+					first = false;
+				}
+				sb.append(colq.substring(0, i));
+				sb.append(".");
+				sb.append(colq.substring(i + 1));
+				sb.append("=");
+				sb.append(e.getValue().toString());
+			}
+		}
+		return sb.toString();
+	}
+	
+	@Test
+	public void testSerializedSingleDuplicate() {
+		Text[] terms = new Text[] {
+			new Text("A"),
+			new Text("A")
+		};
+		
+		String test = "01";
+		Scanner s = setUpIntersectingIterator(getSerializedScanner(), terms, false);
+		s.setRange(new Range());
+		assertTrue(test.equals(checkSerialized(s)));
+	}
+	
+	@Test
+	public void testCellLevelSingleDuplicate() {
+		Text[] terms = new Text[] {
+			new Text("A"),
+			new Text("A")
+		};
+		String test = "01.field0=A,01.field1=B,01.field2=C,01.field3=D,01.field4=E";
+		Scanner s = setUpIntersectingIterator(getCellLevelScanner(), terms, true);
+		s.setRange(new Range());
+		assertTrue(test.equals(checkCellLevel(s)));
+	}
+	
+	@Test
+	public void testSerializedTwoTerms() {
+		Text[] terms = new Text[] {
+			new Text("C"),
+			new Text("D")
+		};
+		// all the evens will come first
+		String test = "02,01,03";
+		Scanner s = setUpIntersectingIterator(getSerializedScanner(), terms, false);
+		s.setRange(new Range());
+		assertTrue(test.equals(checkSerialized(s)));
+	}
+	
+	@Test
+	public void testCellLevelTwoTerms() {
+		Text[] terms = new Text[] {
+			new Text("C"),
+			new Text("D")
+		};
+		
+		String test = "02.field0=B,02.field1=C,02.field2=D,02.field3=E,02.field4=F,"
+			+ "01.field0=A,01.field1=B,01.field2=C,01.field3=D,01.field4=E,"
+			+ "03.field0=C,03.field1=D,03.field2=E,03.field3=F,03.field4=G";
+		Scanner s = setUpIntersectingIterator(getCellLevelScanner(), terms, true);
+		s.setRange(new Range());
+		assertTrue(test.equals(checkCellLevel(s)));
+	}
+	
+	@Test
+	public void testSerializedTwoTermsWithRange() {
+		Text[] terms = new Text[] {
+			new Text("C"),
+			new Text("D")
+		};
+		
+		String test = "02";
+		Scanner s = setUpIntersectingIterator(getSerializedScanner(), terms, false);
+		s.setRange(new Range(new Key(new Text("0")), true, new Key(new Text("1")), false));
+		assertTrue(test.equals(checkSerialized(s)));
+	}
+	
+	@Test
+	public void testCellLevelTwoTermsWithRange() {
+		Text[] terms = new Text[] {
+			new Text("C"),
+			new Text("D")
+		};
+		
+		String test = "02.field0=B,02.field1=C,02.field2=D,02.field3=E,02.field4=F";
+		Scanner s = setUpIntersectingIterator(getCellLevelScanner(), terms, true);
+		s.setRange(new Range(new Key(new Text("0")), true, new Key(new Text("1")), false));
+		assertTrue(test.equals(checkCellLevel(s)));
+	}
+	
+	@Test
+	public void testSerializedSingleRange() {
+		Text[] terms = new Text[] {
+			new Text(GMDenIntersectingIterator.getRangeTerm("index", "A", true, "B", true)),
+			new Text(GMDenIntersectingIterator.getRangeTerm("index", "A", true, "B", true))
+		};
+		
+		String test = "02,01";
+		Scanner s = setUpIntersectingIterator(getSerializedScanner(), terms, false);
+		s.setRange(new Range());
+		assertTrue(test.equals(checkSerialized(s)));
+	}
+	
+	@Test
+	public void testSerializedMultiRange() {
+		Text[] terms = new Text[] {
+			new Text(GMDenIntersectingIterator.getRangeTerm("index", "A", true, "B", true)),
+			new Text(GMDenIntersectingIterator.getRangeTerm("index", "B", true, "C", true))
+		};
+		
+		String test = "02,01";
+		Scanner s = setUpIntersectingIterator(getSerializedScanner(), terms, false);
+		s.setRange(new Range());
+		assertTrue(test.equals(checkSerialized(s)));
+	}
+	
+	@Test
+	public void testSerializedTermAndRange() {
+		Text[] terms = new Text[] {
+			new Text("B"),
+			new Text(GMDenIntersectingIterator.getRangeTerm("index", "A", true, "E", true))
+		};
+		
+		String test = "02,01";
+		Scanner s = setUpIntersectingIterator(getSerializedScanner(), terms, false);
+		s.setRange(new Range());
+		assertTrue(test.equals(checkSerialized(s)));
+	}
+	
+	protected Scanner setUpSortedRangeIterator(Scanner s, boolean multiDoc) {
+		try {
+			s.setScanIterators(50, SortedRangeIterator.class.getName(), "ri");
+			s.setScanIteratorOption("ri", SortedRangeIterator.OPTION_COLF, "index");
+			s.setScanIteratorOption("ri", SortedRangeIterator.OPTION_DOC_COLF, "event");
+			s.setScanIteratorOption("ri", SortedRangeIterator.OPTION_LOWER_BOUND, "A");
+			s.setScanIteratorOption("ri", SortedRangeIterator.OPTION_UPPER_BOUND, "C");
+			s.setScanIteratorOption("ri", SortedRangeIterator.OPTION_START_INCLUSIVE, "true");
+			s.setScanIteratorOption("ri", SortedRangeIterator.OPTION_END_INCLUSIVE, "true");
+			s.setScanIteratorOption("ri", SortedRangeIterator.OPTION_MULTI_DOC, "" + multiDoc);
+			return s;
+		} catch (IOException e) {
+			e.printStackTrace();
+			return null;
+		}
+	}
+	
+	@Test
+	public void testSerializedSortedRangeIterator() {
+		Scanner s = setUpSortedRangeIterator(getSerializedScanner(), false);
+		String test = "02,01,03";
+		s.setRange(new Range());
+		assertTrue(test.equals(checkSerialized(s)));
+	}
+	
+	@Test
+	public void testCellLevelSortedRangeIterator() {
+		Scanner s = setUpSortedRangeIterator(getCellLevelScanner(), true);
+		String test = "02.field0=B,02.field1=C,02.field2=D,02.field3=E,02.field4=F,"
+			+ "01.field0=A,01.field1=B,01.field2=C,01.field3=D,01.field4=E,"
+			+ "03.field0=C,03.field1=D,03.field2=E,03.field3=F,03.field4=G";
+		s.setRange(new Range());
+		assertTrue(test.equals(checkCellLevel(s)));
+	}
+	
+	@Test
+	public void testUniqueIterator() {
+		Scanner s = getProvenanceScanner();
+		try {
+			s.setScanIterators(50, UniqueIterator.class.getName(), "skipper");
+			Key start = new Key(new Text("sid1"));
+			s.setRange(new Range(start, start.followingKey(PartialKey.ROW)));
+			
+			int count = 0;
+			for (Entry<Key, Value> e: s) {
+				count++;
+			}
+			
+			assertEquals(count, 3);
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+	
+	protected Scanner setUpConversionIterator(Scanner s) {
+		String[] conversions = new String[] {
+			"field0 + 10",
+			"field1 - 10",
+			"field2 * 10",
+			"field3 / 10",
+			"field4 % 10"
+		};
+		
+		try {
+			s.setScanIterators(50, ConversionIterator.class.getName(), "ci");
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		
+		s.setScanIteratorOption("ci", ConversionIterator.OPTION_CONVERSIONS, ConversionIterator.encodeConversions(conversions));
+		Key start = new Key(new Text("1"), new Text("event"), new Text("01"));
+		s.setRange(new Range(start, true, start.followingKey(PartialKey.ROW_COLFAM_COLQUAL), false));
+		
+		return s;
+	}
+	
+	@Test
+	public void testConversionIteratorSerialized() {
+		Scanner s = getSerializedScanner();
+		s = setUpConversionIterator(s);
+		
+		CBConverter c = new CBConverter();
+		
+		boolean test = true;
+		Map<String, Double> expected = new HashMap<String, Double>();
+		
+		expected.put("field0", 20.0);
+		expected.put("field1", 1.0);
+		expected.put("field2", 120.0);
+		expected.put("field3", 1.3);
+		expected.put("field4", 4.0);
+		
+		Map<String, String> record;
+		
+		for (Entry<Key, Value> e: s) {
+			record = c.toMap(e.getKey(), e.getValue());
+			
+			for (Entry<String, String> pair: record.entrySet()) {
+				test = test && expected.get(pair.getKey()).equals(new Double(Double.parseDouble(record.get(pair.getKey()))));
+			}
+		}
+		
+		assertTrue(test);
+	}
+	
+	@Test
+	public void testConversionIteratorCellLevel() {
+		Scanner s = getCellLevelScanner();
+		s = setUpConversionIterator(s);
+		s.setScanIteratorOption("ci", ConversionIterator.OPTION_MULTI_DOC, "true");
+		
+		boolean test = true;
+		Map<String, Double> expected = new HashMap<String, Double>();
+		
+		expected.put("field0", 20.0);
+		expected.put("field1", 1.0);
+		expected.put("field2", 120.0);
+		expected.put("field3", 1.3);
+		expected.put("field4", 4.0);
+		
+		for (Entry<Key, Value> e: s) {
+			String field = getField(e.getKey());
+			if (field != null) {
+				test = test && expected.get(field).equals(new Double(Double.parseDouble(e.getValue().toString())));
+			}
+		}
+		
+		assertTrue(test);
+	}
+	
+	protected String getField(Key key) {
+		String colq = key.getColumnQualifier().toString();
+		int start = colq.indexOf("\u0000");
+		if (start == -1) {
+			return null;
+		}
+		
+		int end = colq.indexOf("\u0000", start + 1);
+		if (end == -1) {
+			end = colq.length();
+		}
+		
+		return colq.substring(start + 1, end);
+	}
+	
+	@Test
+	public void testCellLevelOGCFilter() {
+		Scanner s = getCellLevelScanner();
+		s.fetchColumnFamily(new Text("event"));
+		
+		try {
+			s.setScanIterators(60, CellLevelFilteringIterator.class.getName(), "fi");
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		
+		s.setScanIteratorOption("fi", CellLevelFilteringIterator.OPTION_FILTER, "<PropertyIsBetween><PropertyName>field0</PropertyName>"
+			+ "<LowerBoundary><Literal>A</Literal></LowerBoundary>"
+			+ "<UpperBoundary><Literal>C</Literal></UpperBoundary>"
+			+ "</PropertyIsBetween>");
+		
+		String test = "02.field0=B,02.field1=C,02.field2=D,02.field3=E,02.field4=F,"
+			+ "01.field0=A,01.field1=B,01.field2=C,01.field3=D,01.field4=E,"
+			+ "03.field0=C,03.field1=D,03.field2=E,03.field3=F,03.field4=G";
+		assertTrue(test.equals(checkCellLevel(s)));
+	}
+	
+	@Test
+	public void testMultiLevelIterator() {
+		Scanner s = getCellLevelScanner();
+		Text[] terms = new Text[] {
+			new Text("C"),
+			new Text("D")
+		};
+		
+		s = setUpIntersectingIterator(s, terms, true);
+		
+		try {
+			s.setScanIterators(60, CellLevelFilteringIterator.class.getName(), "fi");
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		
+		s.setScanIteratorOption("fi", CellLevelFilteringIterator.OPTION_FILTER, "<PropertyIsEqualTo><PropertyName>field0</PropertyName>"
+			+ "<Literal>A</Literal>"
+			+ "</PropertyIsEqualTo>");
+		
+		String test = "01.field0=A,01.field1=B,01.field2=C,01.field3=D,01.field4=E";
+		assertTrue(test.equals(checkCellLevel(s)));
+	}
+	
+	@Test
+	public void testMultiLevelIterator2() {
+		Scanner s = getCellLevelScanner();
+		s = setUpSortedRangeIterator(s, true);
+		try {
+			s.setScanIterators(60, CellLevelFilteringIterator.class.getName(), "fi");
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		s.setScanIteratorOption("fi", CellLevelFilteringIterator.OPTION_FILTER, "<PropertyIsEqualTo><PropertyName>field0</PropertyName>"
+			+ "<Literal>A</Literal>"
+			+ "</PropertyIsEqualTo>");
+		
+		String test = "01.field0=A,01.field1=B,01.field2=C,01.field3=D,01.field4=E";
+		assertTrue(test.equals(checkCellLevel(s)));
+	}
+	
+	@Test
+	public void testCellLevelRecordIterator() {
+		Scanner s = getCellLevelScanner();
+		s = setUpSortedRangeIterator(s, true);
+		try {
+			s.setScanIterators(60, CellLevelRecordIterator.class.getName(), "recordItr");
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		
+//		for (Entry<Key, Value> e: s) {
+//			String v = e.getValue().toString();
+//			v = v.replaceAll("\\u0000", ",");
+//			v = v.replaceAll("\\uFFFD", "=");
+//			System.out.println(e.getKey() + "\t" + v);
+//		}
+		String test = "02,01,03";
+		assertTrue(test.equals(checkSerialized(s)));
+	}
+	
+	@Test
+	public void testIntersectionWithoutDocLookup() {
+		Text[] terms = new Text[] {
+			new Text("C"),
+			new Text("D")
+		};
+		// all the evens will come first
+		String test = "\u000002,\u000001,\u000003";
+		Scanner s = setUpIntersectingIterator(getSerializedScanner(), terms, false);
+		s.setScanIteratorOption("ii", GMDenIntersectingIterator.OPTION_DOC_LOOKUP, "false");
+		s.setRange(new Range());
+		assertTrue(test.equals(checkSerialized(s)));
+	}
+	
+	@Test
+	public void testSimpleNot() {
+		Text[] terms = new Text[] {
+			new Text("B"),
+			new Text("F")
+		};
+		
+		boolean[] nots = new boolean[] {
+			false,
+			true
+		};
+		
+		String test="01";
+		Scanner s = setUpIntersectingIterator(getSerializedScanner(), terms, false);
+		s.setScanIteratorOption("ii", GMDenIntersectingIterator.notFlagOptionName, GMDenIntersectingIterator.encodeBooleans(nots));
+		s.setRange(new Range());
+		
+		assertTrue(test.equals(checkSerialized(s)));
+	}
+	
+	@Test
+	public void testRangeNot() {
+		Text[] terms = new Text[] {
+			new Text("B"),
+			new Text(GMDenIntersectingIterator.getRangeTerm("index", "F", true, "H", true))
+		};
+		
+		boolean[] nots = new boolean[] {
+			false,
+			true
+		};
+		
+		String test = "01";
+		Scanner s = setUpIntersectingIterator(getSerializedScanner(), terms, false);
+		s.setScanIteratorOption("ii", GMDenIntersectingIterator.notFlagOptionName, GMDenIntersectingIterator.encodeBooleans(nots));
+		s.setRange(new Range());
+		
+		assertTrue(test.equals(checkSerialized(s)));
+	}
+	
+	@Test
+	public void testMinIteratorOnLastKeys() {
+		Scanner s = getSerializedScanner();
+		try {
+			s.setScanIterators(50, SortedMinIterator.class.getName(), "min");
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		s.setScanIteratorOption("min", SortedMinIterator.OPTION_PREFIX, "z");
+		s.setRange(new Range());
+		
+		String test = "02,04,06,08,10,01,03,05,07,09";
+		assertTrue(test.equals(checkSerialized(s)));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/test/java/JTSFilterTest.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/test/java/JTSFilterTest.java b/partition/common-query/src/test/java/JTSFilterTest.java
new file mode 100644
index 0000000..8224f64
--- /dev/null
+++ b/partition/common-query/src/test/java/JTSFilterTest.java
@@ -0,0 +1,181 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Map.Entry;
+
+import org.apache.hadoop.io.Text;
+import org.junit.Test;
+
+import ss.cloudbase.core.iterators.GMDenIntersectingIterator;
+import ss.cloudbase.core.iterators.filter.jts.JTSFilter;
+
+import cloudbase.core.client.Connector;
+import cloudbase.core.client.Scanner;
+import cloudbase.core.client.TableNotFoundException;
+import cloudbase.core.data.Key;
+import cloudbase.core.data.Range;
+import cloudbase.core.data.Value;
+import cloudbase.core.iterators.FilteringIterator;
+import cloudbase.core.security.Authorizations;
+
+/**
+ *
+ * @author rashah
+ */
+public class JTSFilterTest
+{
+
+  private Connector cellLevelConn;
+  private Connector serializedConn;
+  private static final String TABLE = "partition";
+  private static final Authorizations AUTHS = new Authorizations("ALPHA,BETA,GAMMA".split(","));
+
+
+
+  protected Connector getSerializedConnector()
+  {
+    if (serializedConn == null)
+    {
+      serializedConn = SampleJTSData.initConnector();
+      SampleJTSData.writeDenSerialized(serializedConn, SampleJTSData.sampleData());
+    }
+    return serializedConn;
+  }
+
+
+
+  protected Scanner getSerializedScanner()
+  {
+    Connector c = getSerializedConnector();
+    try
+    {
+      return c.createScanner(TABLE, AUTHS);
+    }
+    catch (TableNotFoundException e)
+    {
+      return null;
+    }
+  }
+
+  protected Scanner setUpJTSFilter(Scanner s, String latitude, String longitude, boolean change_name)
+  {
+    try
+    {
+  
+      s.setScanIterators(50, FilteringIterator.class.getName(), "gvdf");
+      s.setScanIteratorOption("gvdf", "0", JTSFilter.class.getName());
+      s.setScanIteratorOption("gvdf", "0." + JTSFilter.OPTIONCenterPointLat, latitude);
+      s.setScanIteratorOption("gvdf", "0." + JTSFilter.OPTIONCenterPointLon, longitude);
+      if (change_name)
+          s.setScanIteratorOption("gvdf", "0." + JTSFilter.OPTIONGeometryKeyName, "beam-footprint");
+
+
+    }
+    catch (IOException e)
+    {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
+    return s;
+  }
+
+  protected String checkSerialized(Scanner s)
+  {
+    StringBuilder sb = new StringBuilder();
+    boolean first = true;
+    for (Entry<Key, Value> e : s)
+    {
+
+      if (!first)
+      {
+        sb.append(",");
+      }
+      else
+      {
+        first = false;
+      }
+
+      String colq = e.getKey().getColumnQualifier().toString();
+
+      sb.append(colq);
+    }
+    return sb.toString();
+  }
+
+
+  @Test
+  public void testNoResults()
+  {
+    //London is in niether - 51°30'0.00"N   0° 7'0.00"W
+    String latitude = "51.5";
+    String longitude = "0.11";
+
+    Scanner s = setUpJTSFilter(getSerializedScanner(), latitude, longitude, false);
+    s.setRange(new Range());
+
+//    System.out.println("{" + checkSerialized(s) + "}");
+    assertTrue(checkSerialized(s).isEmpty());
+  }
+
+
+  @Test
+  public void testOneResultAmerica()
+  {
+    //This is North America
+    //Points  39°44'21.00"N 104°59'3.00"W (Denver) are in the footprint
+    String latitude = "33";
+    String longitude = "-93.0";
+
+    Scanner s = setUpJTSFilter(getSerializedScanner(), latitude, longitude, false);
+    s.setRange(new Range());
+
+    System.out.println("{" + checkSerialized(s) + "}");
+    assertTrue(checkSerialized(s).equals("02"));
+  }
+
+
+  @Test
+  public void testOneResultAustralia()
+  {
+    //This is Australia
+    //Points like 22S 135E are in the beam
+    String latitude = "-9";
+    String longitude = "100.0";
+
+    Scanner s = setUpJTSFilter(getSerializedScanner(), latitude, longitude, false);
+    s.setRange(new Range());
+
+    System.out.println("{" + checkSerialized(s) + "}");
+    assertTrue(checkSerialized(s).equals("01"));
+  }
+
+  @Test
+  public void testOneResultHawaii()
+  {
+    // -164 40 - somewhere near hawaii
+
+    //This is Australia
+    //Points like 22S 135E are in the beam
+    String latitude = "40";
+    String longitude = "-164.0";
+
+    Scanner s = setUpJTSFilter(getSerializedScanner(), latitude, longitude, true);
+    s.setRange(new Range());
+
+    System.out.println("{" + checkSerialized(s) + "}");
+    assertTrue(checkSerialized(s).equals("03"));
+  }
+
+
+  @Test
+  public void testDummyTest()
+  {
+    assertTrue(true);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/partition/common-query/src/test/java/OGCFilterTest.java
----------------------------------------------------------------------
diff --git a/partition/common-query/src/test/java/OGCFilterTest.java b/partition/common-query/src/test/java/OGCFilterTest.java
new file mode 100644
index 0000000..fd54945
--- /dev/null
+++ b/partition/common-query/src/test/java/OGCFilterTest.java
@@ -0,0 +1,163 @@
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.hadoop.io.Text;
+import org.junit.Test;
+
+import cloudbase.core.data.Key;
+import cloudbase.core.data.Value;
+import ss.cloudbase.core.iterators.filter.ogc.OGCFilter;
+
+import static org.junit.Assert.*;
+
+public class OGCFilterTest {
+	private Key testKey = new Key(new Text("row"), new Text("colf"), new Text("colq"));
+	private Value testValue = new Value("uuid~event\uFFFDmy-event-hash-1\u0000date\uFFFD20100819\u0000time~dss\uFFFD212706.000\u0000frequency\uFFFD3.368248181443644E8\u0000latitude\uFFFD48.74571142707959\u0000longitude\uFFFD13.865561564126812\u0000altitude\uFFFD1047.0\u0000datetime\uFFFD2010-08-19T21:27:06.000Z\u0000test~key\uFFFD\u0000key\uFFFDa\uFFFDb".getBytes());
+
+	public OGCFilterTest() {
+
+	}
+
+	private OGCFilter getFilter(String filter) {
+		OGCFilter f = new OGCFilter();
+		Map<String, String> options = new HashMap<String, String>();
+		options.put(OGCFilter.OPTION_FILTER, filter);
+		f.init(options);
+		return f;
+	}
+
+	@Test
+	public void testBBOX() {
+		OGCFilter f = getFilter("<BBOX><gml:Envelope>"
+			+ "<gml:LowerCorner>13 48</gml:LowerCorner>"
+			+ "<gml:UpperCorner>14 49</gml:UpperCorner>"
+			+ "</gml:Envelope></BBOX>");
+		assertTrue(f.accept(testKey, testValue));
+	}
+
+	@Test
+	public void testBetweenStr() {
+		OGCFilter f = getFilter("<PropertyIsBetween><PropertyName>datetime</PropertyName>"
+			+ "<LowerBoundary><Literal>2010-08-19</Literal></LowerBoundary>"
+			+ "<UpperBoundary><Literal>2010-08-20</Literal></UpperBoundary>"
+			+ "</PropertyIsBetween>");
+
+		assertTrue(f.accept(testKey, testValue));
+	}
+
+	@Test
+	public void testBetweenNum() {
+		OGCFilter f = getFilter("<PropertyIsBetween><PropertyName>frequency</PropertyName>"
+			+ "<LowerBoundary><Literal>330000000</Literal></LowerBoundary>"
+			+ "<UpperBoundary><Literal>340000000</Literal></UpperBoundary>"
+			+ "</PropertyIsBetween>");
+
+		assertTrue(f.accept(testKey, testValue));
+	}
+
+	@Test
+	public void testEqualStr() {
+		OGCFilter f = getFilter("<PropertyIsEqualTo><PropertyName>uuid~event</PropertyName><Literal>my-event-hash-1</Literal></PropertyIsEqualTo>");
+		assertTrue(f.accept(testKey, testValue));
+	}
+
+	@Test
+	public void testEqualNum() {
+		OGCFilter f = getFilter("<PropertyIsEqualTo><PropertyName>altitude</PropertyName><Literal>1047</Literal></PropertyIsEqualTo>");
+		assertTrue(f.accept(testKey, testValue));
+	}
+
+	@Test
+	public void testGreaterThanStr() {
+		OGCFilter f = getFilter("<PropertyIsGreaterThan><PropertyName>datetime</PropertyName><Literal>2010-08-15</Literal></PropertyIsGreaterThan>");
+		assertTrue(f.accept(testKey, testValue));
+	}
+
+	@Test
+	public void testGreaterThanNum() {
+		OGCFilter f = getFilter("<PropertyIsGreaterThan><PropertyName>altitude</PropertyName><Literal>1000</Literal></PropertyIsGreaterThan>");
+		assertTrue(f.accept(testKey, testValue));
+	}
+
+	@Test
+	public void testLessThanStr() {
+		OGCFilter f = getFilter("<PropertyIsLessThan><PropertyName>datetime</PropertyName><Literal>2010-08-20</Literal></PropertyIsLessThan>");
+		assertTrue(f.accept(testKey, testValue));
+	}
+
+	@Test
+	public void testLessThanNum() {
+		OGCFilter f = getFilter("<PropertyIsLessThan><PropertyName>altitude</PropertyName><Literal>1200</Literal></PropertyIsLessThan>");
+		assertTrue(f.accept(testKey, testValue));
+	}
+
+	@Test
+	public void testLike() {
+		OGCFilter f = getFilter("<PropertyIsLike><PropertyName>uuid~event</PropertyName><Literal>*event*</Literal></PropertyIsLike>");
+		assertTrue(f.accept(testKey, testValue));
+	}
+
+	@Test
+	public void testNotEqualNum() {
+		OGCFilter f = getFilter("<PropertyIsNotEqualTo><PropertyName>altitude</PropertyName><Literal>1046</Literal></PropertyIsNotEqualTo>");
+		assertTrue(f.accept(testKey, testValue));
+	}
+
+	@Test
+	public void testNull() {
+		OGCFilter f = getFilter("<PropertyIsNull><PropertyName>test~key</PropertyName></PropertyIsNull>");
+		assertTrue(f.accept(testKey, testValue));
+	}
+
+	@Test
+	public void testNot() {
+		OGCFilter f = getFilter("<Not><PropertyIsEqualTo><PropertyName>altitude</PropertyName><Literal>1047</Literal></PropertyIsEqualTo></Not>");
+		assertFalse(f.accept(testKey, testValue));
+	}
+
+	@Test
+	public void testAnd() {
+		OGCFilter f = getFilter("<And>"
+			+ "<PropertyIsEqualTo><PropertyName>altitude</PropertyName><Literal>1047</Literal></PropertyIsEqualTo>"
+			+ "<PropertyIsNull><PropertyName>test~key</PropertyName></PropertyIsNull>"
+			+ "</And>");
+
+		assertTrue(f.accept(testKey, testValue));
+	}
+
+	@Test
+	public void testOr() {
+		OGCFilter f = getFilter("<Or>"
+			+ "<PropertyIsLike><PropertyName>uuid~event</PropertyName><Literal>*event*</Literal></PropertyIsLike>"
+			+ "<PropertyIsNull><PropertyName>uuid~event</PropertyName></PropertyIsNull>"
+			+ "</Or>");
+
+		assertTrue(f.accept(testKey, testValue));
+	}
+
+	@Test
+	public void testNand() {
+		OGCFilter f = getFilter("<Not><And>"
+			+ "<PropertyIsNull><PropertyName>uuid~event</PropertyName></PropertyIsNull>"
+			+ "<PropertyIsNull><PropertyName>test~key</PropertyName></PropertyIsNull>"
+			+ "</And></Not>");
+
+		assertTrue(f.accept(testKey, testValue));
+	}
+
+	@Test
+	public void testNor() {
+		OGCFilter f = getFilter("<Not>"
+			+ "<PropertyIsNull><PropertyName>uuid~event</PropertyName></PropertyIsNull>"
+			+ "<PropertyIsNull><PropertyName>altitude</PropertyName></PropertyIsNull>"
+			+ "</Not>");
+
+		assertTrue(f.accept(testKey, testValue));
+	}
+
+	@Test
+	public void testParse() {
+		OGCFilter f = getFilter("<PropertyIsEqualTo><PropertyName>key</PropertyName><Literal>a</Literal></PropertyIsEqualTo>");
+		assertTrue(f.accept(testKey, testValue));
+	}
+}