You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by bi...@apache.org on 2011/12/05 21:05:51 UTC

svn commit: r1210600 [13/16] - in /incubator/accumulo/trunk/contrib/accumulo_sample: ./ ingest/ ingest/src/main/java/aggregator/ ingest/src/main/java/ingest/ ingest/src/main/java/iterator/ ingest/src/main/java/normalizer/ ingest/src/main/java/protobuf/...

Modified: incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/parser/JexlOperatorConstants.java
URL: http://svn.apache.org/viewvc/incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/parser/JexlOperatorConstants.java?rev=1210600&r1=1210599&r2=1210600&view=diff
==============================================================================
--- incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/parser/JexlOperatorConstants.java (original)
+++ incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/parser/JexlOperatorConstants.java Mon Dec  5 20:05:49 2011
@@ -1,19 +1,19 @@
 /*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package parser;
 
 import java.util.Map;
@@ -34,72 +34,72 @@ import org.apache.commons.jexl2.parser.J
 import org.apache.commons.jexl2.parser.ParserTreeConstants;
 
 public class JexlOperatorConstants implements ParserTreeConstants {
-
-	private static Map<Class<? extends JexlNode>,String> operatorMap = new ConcurrentHashMap<Class<? extends JexlNode>,String>();
-	private static Map<String, Class<? extends JexlNode>> classMap = new ConcurrentHashMap<String, Class<? extends JexlNode>>();
-	private static Map<Integer,String> jjtOperatorMap = new ConcurrentHashMap<Integer,String>();
-	private static Map<String,Integer> jjtTypeMap = new ConcurrentHashMap<String,Integer>();
-
-	static {
-		operatorMap.put(ASTEQNode.class, "==");
-		operatorMap.put(ASTNENode.class, "!=");
-		operatorMap.put(ASTLTNode.class, "<");
-		operatorMap.put(ASTLENode.class, "<=");
-		operatorMap.put(ASTGTNode.class, ">");
-		operatorMap.put(ASTGENode.class, ">=");
-		operatorMap.put(ASTERNode.class, "=~");
-		operatorMap.put(ASTNRNode.class, "!~");
-		operatorMap.put(ASTFunctionNode.class, "f");
-        operatorMap.put(ASTAndNode.class,"and");
-        operatorMap.put(ASTOrNode.class,"or");
-        
-		classMap.put("==", ASTEQNode.class);
-		classMap.put("!=", ASTNENode.class);
-		classMap.put("<", ASTLTNode.class);
-		classMap.put("<=", ASTLENode.class);
-		classMap.put(">", ASTGTNode.class);
-		classMap.put(">=", ASTGENode.class);
-		classMap.put("=~", ASTERNode.class);
-		classMap.put("!~", ASTNRNode.class);
-		classMap.put("f", ASTFunctionNode.class);
-
-		jjtOperatorMap.put(JJTEQNODE, "==");
-		jjtOperatorMap.put(JJTNENODE, "!=");
-		jjtOperatorMap.put(JJTLTNODE, "<");
-		jjtOperatorMap.put(JJTLENODE, "<=");
-		jjtOperatorMap.put(JJTGTNODE, ">");
-		jjtOperatorMap.put(JJTGENODE, ">=");
-		jjtOperatorMap.put(JJTERNODE, "=~");
-		jjtOperatorMap.put(JJTNRNODE, "!~");
-		jjtOperatorMap.put(JJTFUNCTIONNODE, "f");
-        jjtOperatorMap.put(JJTANDNODE, "and");
-        jjtOperatorMap.put(JJTORNODE, "or");
-
-		jjtTypeMap.put("==", JJTEQNODE);
-		jjtTypeMap.put("!=", JJTNENODE);
-		jjtTypeMap.put("<", JJTLTNODE);
-		jjtTypeMap.put("<=", JJTLENODE);
-		jjtTypeMap.put(">", JJTGTNODE);
-		jjtTypeMap.put(">=", JJTGENODE);
-		jjtTypeMap.put("=~", JJTERNODE);
-		jjtTypeMap.put("!~", JJTNRNODE);
-		jjtTypeMap.put("f", JJTFUNCTIONNODE);
-
-	}
-
-	public static String getOperator(Class<? extends JexlNode> nodeType) {
-		return operatorMap.get(nodeType);
-	}
-	
-	public static String getOperator(Integer jjtNode) {
-		return jjtOperatorMap.get(jjtNode);
-	}
-	
-	public static Class<? extends JexlNode> getClass(String operator) {
-		return classMap.get(operator);
-	}
-	
-	public static int getJJTNodeType(String operator) {
-		return jjtTypeMap.get(operator);
-	}
+  
+  private static Map<Class<? extends JexlNode>,String> operatorMap = new ConcurrentHashMap<Class<? extends JexlNode>,String>();
+  private static Map<String,Class<? extends JexlNode>> classMap = new ConcurrentHashMap<String,Class<? extends JexlNode>>();
+  private static Map<Integer,String> jjtOperatorMap = new ConcurrentHashMap<Integer,String>();
+  private static Map<String,Integer> jjtTypeMap = new ConcurrentHashMap<String,Integer>();
+  
+  static {
+    operatorMap.put(ASTEQNode.class, "==");
+    operatorMap.put(ASTNENode.class, "!=");
+    operatorMap.put(ASTLTNode.class, "<");
+    operatorMap.put(ASTLENode.class, "<=");
+    operatorMap.put(ASTGTNode.class, ">");
+    operatorMap.put(ASTGENode.class, ">=");
+    operatorMap.put(ASTERNode.class, "=~");
+    operatorMap.put(ASTNRNode.class, "!~");
+    operatorMap.put(ASTFunctionNode.class, "f");
+    operatorMap.put(ASTAndNode.class, "and");
+    operatorMap.put(ASTOrNode.class, "or");
+    
+    classMap.put("==", ASTEQNode.class);
+    classMap.put("!=", ASTNENode.class);
+    classMap.put("<", ASTLTNode.class);
+    classMap.put("<=", ASTLENode.class);
+    classMap.put(">", ASTGTNode.class);
+    classMap.put(">=", ASTGENode.class);
+    classMap.put("=~", ASTERNode.class);
+    classMap.put("!~", ASTNRNode.class);
+    classMap.put("f", ASTFunctionNode.class);
+    
+    jjtOperatorMap.put(JJTEQNODE, "==");
+    jjtOperatorMap.put(JJTNENODE, "!=");
+    jjtOperatorMap.put(JJTLTNODE, "<");
+    jjtOperatorMap.put(JJTLENODE, "<=");
+    jjtOperatorMap.put(JJTGTNODE, ">");
+    jjtOperatorMap.put(JJTGENODE, ">=");
+    jjtOperatorMap.put(JJTERNODE, "=~");
+    jjtOperatorMap.put(JJTNRNODE, "!~");
+    jjtOperatorMap.put(JJTFUNCTIONNODE, "f");
+    jjtOperatorMap.put(JJTANDNODE, "and");
+    jjtOperatorMap.put(JJTORNODE, "or");
+    
+    jjtTypeMap.put("==", JJTEQNODE);
+    jjtTypeMap.put("!=", JJTNENODE);
+    jjtTypeMap.put("<", JJTLTNODE);
+    jjtTypeMap.put("<=", JJTLENODE);
+    jjtTypeMap.put(">", JJTGTNODE);
+    jjtTypeMap.put(">=", JJTGENODE);
+    jjtTypeMap.put("=~", JJTERNODE);
+    jjtTypeMap.put("!~", JJTNRNODE);
+    jjtTypeMap.put("f", JJTFUNCTIONNODE);
+    
+  }
+  
+  public static String getOperator(Class<? extends JexlNode> nodeType) {
+    return operatorMap.get(nodeType);
+  }
+  
+  public static String getOperator(Integer jjtNode) {
+    return jjtOperatorMap.get(jjtNode);
+  }
+  
+  public static Class<? extends JexlNode> getClass(String operator) {
+    return classMap.get(operator);
+  }
+  
+  public static int getJJTNodeType(String operator) {
+    return jjtTypeMap.get(operator);
+  }
 }

Modified: incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/parser/QueryEvaluator.java
URL: http://svn.apache.org/viewvc/incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/parser/QueryEvaluator.java?rev=1210600&r1=1210599&r2=1210600&view=diff
==============================================================================
--- incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/parser/QueryEvaluator.java (original)
+++ incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/parser/QueryEvaluator.java Mon Dec  5 20:05:49 2011
@@ -1,19 +1,19 @@
 /*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package parser;
 
 import java.util.Collection;
@@ -43,252 +43,250 @@ import com.google.common.collect.Multima
 import function.QueryFunctions;
 
 /**
- * This class evaluates events against a query. The query is passed to the constructor and then
- * parsed. It is evaluated against an event in the evaluate method.
+ * This class evaluates events against a query. The query is passed to the constructor and then parsed. It is evaluated against an event in the evaluate method.
  */
 public class QueryEvaluator {
-
-    private static Logger log = Logger.getLogger(QueryEvaluator.class);
-    //According to the JEXL 2.0 docs, the engine is thread-safe. Let's create 1 engine per VM and
-    //cache 128 expressions
-    private static JexlEngine engine = new JexlEngine(null, new Arithmetic(false), null, null);
-
-    static {
-        engine.setSilent(false);
-        engine.setCache(128);
-        Map<String, Object> functions = new HashMap<String, Object>();
-        functions.put("f", QueryFunctions.class);
-        engine.setFunctions(functions);
-    }
-    private String query = null;
-    private Set<String> literals = null;
-    private Multimap<String, QueryTerm> terms = null;
-    private String modifiedQuery = null;
-    private JexlContext ctx = new MapContext();
-    private boolean caseInsensitive = true;
-
-    public QueryEvaluator(String query) throws ParseException {
-        this.caseInsensitive = true; // default case insensitive matching.
-        if(caseInsensitive){
-            query = query.toLowerCase();
-        }
-        this.query = query;
-        QueryParser parser = new QueryParser();
-        parser.execute(query);
-        this.terms = parser.getQueryTerms();
-        if(caseInsensitive){
-            literals = new HashSet<String>();
-            for(String lit : parser.getQueryIdentifiers()){
-                literals.add(lit.toLowerCase());
-            }
-        }else{
-            this.literals = parser.getQueryIdentifiers();
-        }
+  
+  private static Logger log = Logger.getLogger(QueryEvaluator.class);
+  // According to the JEXL 2.0 docs, the engine is thread-safe. Let's create 1 engine per VM and
+  // cache 128 expressions
+  private static JexlEngine engine = new JexlEngine(null, new Arithmetic(false), null, null);
+  
+  static {
+    engine.setSilent(false);
+    engine.setCache(128);
+    Map<String,Object> functions = new HashMap<String,Object>();
+    functions.put("f", QueryFunctions.class);
+    engine.setFunctions(functions);
+  }
+  private String query = null;
+  private Set<String> literals = null;
+  private Multimap<String,QueryTerm> terms = null;
+  private String modifiedQuery = null;
+  private JexlContext ctx = new MapContext();
+  private boolean caseInsensitive = true;
+  
+  public QueryEvaluator(String query) throws ParseException {
+    this.caseInsensitive = true; // default case insensitive matching.
+    if (caseInsensitive) {
+      query = query.toLowerCase();
     }
-
-    public QueryEvaluator(String query, boolean insensitive) throws ParseException {
-        this.caseInsensitive = insensitive;
-        if(this.caseInsensitive){
-            query = query.toLowerCase();
-        }
-        this.query = query;
-        QueryParser parser = new QueryParser();
-        parser.execute(query);
-        this.terms = parser.getQueryTerms();
-
-        if(caseInsensitive){
-            literals = new HashSet<String>();
-            for(String lit : parser.getQueryIdentifiers()){
-                literals.add(lit.toLowerCase());
-            }
-        }else{
-            this.literals = parser.getQueryIdentifiers();
-        }
+    this.query = query;
+    QueryParser parser = new QueryParser();
+    parser.execute(query);
+    this.terms = parser.getQueryTerms();
+    if (caseInsensitive) {
+      literals = new HashSet<String>();
+      for (String lit : parser.getQueryIdentifiers()) {
+        literals.add(lit.toLowerCase());
+      }
+    } else {
+      this.literals = parser.getQueryIdentifiers();
     }
-
-    public String getQuery() {
-        return this.query;
+  }
+  
+  public QueryEvaluator(String query, boolean insensitive) throws ParseException {
+    this.caseInsensitive = insensitive;
+    if (this.caseInsensitive) {
+      query = query.toLowerCase();
     }
-
-    public void printLiterals() {
-        for (String s : literals) {
-            System.out.println("literal: " + s);
-        }
+    this.query = query;
+    QueryParser parser = new QueryParser();
+    parser.execute(query);
+    this.terms = parser.getQueryTerms();
+    
+    if (caseInsensitive) {
+      literals = new HashSet<String>();
+      for (String lit : parser.getQueryIdentifiers()) {
+        literals.add(lit.toLowerCase());
+      }
+    } else {
+      this.literals = parser.getQueryIdentifiers();
     }
-
-    public void setLevel(Level lev){
-        log.setLevel(lev);
+  }
+  
+  public String getQuery() {
+    return this.query;
+  }
+  
+  public void printLiterals() {
+    for (String s : literals) {
+      System.out.println("literal: " + s);
+    }
+  }
+  
+  public void setLevel(Level lev) {
+    log.setLevel(lev);
+  }
+  
+  public StringBuilder rewriteQuery(StringBuilder query, String fieldName, Collection<FieldValue> fieldValues) {
+    if (log.isDebugEnabled()) {
+      log.debug("rewriteQuery");
+    }
+    // Here we have a field that has multiple values. In this case we need to put
+    // all values into the jexl context as an array and rewrite the query to account for all
+    // of the fields.
+    if (caseInsensitive) {
+      fieldName = fieldName.toLowerCase();
+    }
+    if (log.isDebugEnabled()) {
+      log.debug("Modifying original query: " + query);
     }
+    // Pull the values out of the FieldValue object
+    String[] values = new String[fieldValues.size()];
+    int idx = 0;
+    for (FieldValue fv : fieldValues) {
+      if (caseInsensitive) {
+        values[idx] = (new String(fv.getValue())).toLowerCase();
+      } else {
+        values[idx] = new String(fv.getValue());
+      }
+      idx++;
+    }
+    // Add the array to the context
+    ctx.set(fieldName, values);
     
-    public StringBuilder rewriteQuery(StringBuilder query, String fieldName, Collection<FieldValue> fieldValues) {
-        if(log.isDebugEnabled()){
-            log.debug("rewriteQuery");
-        }
-        //Here we have a field that has multiple values. In this case we need to put
-        //all values into the jexl context as an array and rewrite the query to account for all
-        //of the fields.
-        if (caseInsensitive) {
-            fieldName = fieldName.toLowerCase();
-        }
-        if (log.isDebugEnabled()) {
-            log.debug("Modifying original query: " + query);
-        }
-        //Pull the values out of the FieldValue object
-        String[] values = new String[fieldValues.size()];
-        int idx = 0;
-        for (FieldValue fv : fieldValues) {
-            if(caseInsensitive){
-                values[idx] = (new String(fv.getValue())).toLowerCase();
-            }else{
-                values[idx] = new String(fv.getValue());
-            }
-            idx++;
-        }
-        //Add the array to the context
-        ctx.set(fieldName, values);
-
-        Collection<QueryTerm> qt = terms.get(fieldName);
-
-        //Add a script to the beginning of the query for this multi-valued field
-        StringBuilder script = new StringBuilder();
-        script.append("_").append(fieldName).append(" = false;\n");
-        script.append("for (field : ").append(fieldName).append(") {\n");
-
-        for (QueryTerm t : qt) {
-        	if (!t.getOperator().equals(JexlOperatorConstants.getOperator(ParserTreeConstants.JJTFUNCTIONNODE))) {
-        		script.append("\tif (_").append(fieldName).append(" == false && field ").append(t.getOperator()).append(" ").append(t.getValue()).append(") { \n");
-        	} else {
-        		script.append("\tif (_").append(fieldName).append(" == false && ").append(t.getValue().toString().replace(fieldName, "field")).append(") { \n");
-        	}
-            script.append("\t\t_").append(fieldName).append(" = true;\n");
-            script.append("\t}\n");
-        }
-        script.append("}\n");
-
-        //Add the script to the beginning of the query
-        query.insert(0, script.toString());
-
-        StringBuilder newPredicate = new StringBuilder();
-        newPredicate.append("_").append(fieldName).append(" == true");
-
-        for (QueryTerm t : qt) {
-            //Find the location of this term in the query
-            StringBuilder predicate = new StringBuilder();
-            int start = 0;
-        	if (!t.getOperator().equals(JexlOperatorConstants.getOperator(ParserTreeConstants.JJTFUNCTIONNODE))) {
-        		predicate.append(fieldName).append(" ").append(t.getOperator()).append(" ").append(t.getValue());
-        		start = query.indexOf(predicate.toString());
-        	} else {
-        		predicate.append(t.getValue().toString());
-        		//need to find the second occurence of the string.
-        		start = query.indexOf(predicate.toString());
-        	}
-        	if (-1 == start) {
-        		log.warn("Unable to find predicate: " + predicate.toString() +" in rewritten query: " + query.toString());
-        	}
-            int length = predicate.length();
-
-            //Now modify the query to check the value of my.fieldName
-            query.replace(start, start + length, newPredicate.toString());
-        }
-
-        if(log.isDebugEnabled()){
-            log.debug("leaving rewriteQuery with: "+query.toString());
-        }
-        return query;
+    Collection<QueryTerm> qt = terms.get(fieldName);
+    
+    // Add a script to the beginning of the query for this multi-valued field
+    StringBuilder script = new StringBuilder();
+    script.append("_").append(fieldName).append(" = false;\n");
+    script.append("for (field : ").append(fieldName).append(") {\n");
+    
+    for (QueryTerm t : qt) {
+      if (!t.getOperator().equals(JexlOperatorConstants.getOperator(ParserTreeConstants.JJTFUNCTIONNODE))) {
+        script.append("\tif (_").append(fieldName).append(" == false && field ").append(t.getOperator()).append(" ").append(t.getValue()).append(") { \n");
+      } else {
+        script.append("\tif (_").append(fieldName).append(" == false && ").append(t.getValue().toString().replace(fieldName, "field")).append(") { \n");
+      }
+      script.append("\t\t_").append(fieldName).append(" = true;\n");
+      script.append("\t}\n");
     }
-
-    /**
-     * Evaluates the query against an event.
-     *
-     * @param eventFields
-     * @return
-     */
-    public boolean evaluate(EventFields eventFields) {
-
-        this.modifiedQuery = null;
-        boolean rewritten = false;
-
-        //Copy the query
-        StringBuilder q = new StringBuilder(query);
-        //Copy the literals, we are going to remove elements from this set
-        //when they are added to the JEXL context. This will allow us to
-        //determine which items in the query where *NOT* in the data.
-        HashSet<String> literalsCopy = new HashSet<String>(literals);
-
-        //Loop through the event fields and add them to the JexlContext.
-        for (Entry<String, Collection<FieldValue>> field : eventFields.asMap().entrySet()) {
-            String fName = field.getKey();
-            if(caseInsensitive){
-                fName = fName.toLowerCase();
-            }
-            //If this field is not part of the expression, then skip it.
-            if (!literals.contains(fName)) {
-                continue;
-            } else {
-                literalsCopy.remove(fName);
-            }
-
-            //This field may have multiple values.
-            if (field.getValue().size() == 0) {
-                continue;
-            } else if (field.getValue().size() == 1) {
-                //We are explicitly converting these bytes to a String.
-                if(caseInsensitive){
-                    ctx.set(field.getKey().toLowerCase(), (new String(field.getValue().iterator().next().getValue())).toLowerCase());
-                }else{
-                    ctx.set(field.getKey(), new String(field.getValue().iterator().next().getValue()));
-                }
-
-            } else {
-                //q = queryRewrite(q, field.getKey(), field.getValue());
-                q = rewriteQuery(q, field.getKey(), field.getValue());
-                rewritten = true;
-            }//End of if
-
-        }//End of loop
-
-        //For any literals in the query that were not found in the data, add them to the context
-        //with a null value.
-        for (String lit : literalsCopy) {
-            ctx.set(lit, null);
-        }
-
-        if (log.isDebugEnabled()) {
-            log.debug("Evaluating query: " + q.toString());
-        }
-
-        this.modifiedQuery = q.toString();
-
-
-        Boolean result = null;
-        if (rewritten) {
-            Script script = engine.createScript(this.modifiedQuery);
-            try {
-                result = (Boolean) script.execute(ctx);
-            } catch (Exception e) {
-                log.error("Error evaluating script: " + this.modifiedQuery + " against event" + eventFields.toString(), e);
-            }
-        } else {
-            Expression expr = engine.createExpression(this.modifiedQuery);
-            try {
-                result = (Boolean) expr.evaluate(ctx);
-            } catch (Exception e) {
-                log.error("Error evaluating expression: " + this.modifiedQuery + " against event" + eventFields.toString(), e);
-            }
-        }
-        if (null != result && result) {
-            return true;
+    script.append("}\n");
+    
+    // Add the script to the beginning of the query
+    query.insert(0, script.toString());
+    
+    StringBuilder newPredicate = new StringBuilder();
+    newPredicate.append("_").append(fieldName).append(" == true");
+    
+    for (QueryTerm t : qt) {
+      // Find the location of this term in the query
+      StringBuilder predicate = new StringBuilder();
+      int start = 0;
+      if (!t.getOperator().equals(JexlOperatorConstants.getOperator(ParserTreeConstants.JJTFUNCTIONNODE))) {
+        predicate.append(fieldName).append(" ").append(t.getOperator()).append(" ").append(t.getValue());
+        start = query.indexOf(predicate.toString());
+      } else {
+        predicate.append(t.getValue().toString());
+        // need to find the second occurence of the string.
+        start = query.indexOf(predicate.toString());
+      }
+      if (-1 == start) {
+        log.warn("Unable to find predicate: " + predicate.toString() + " in rewritten query: " + query.toString());
+      }
+      int length = predicate.length();
+      
+      // Now modify the query to check the value of my.fieldName
+      query.replace(start, start + length, newPredicate.toString());
+    }
+    
+    if (log.isDebugEnabled()) {
+      log.debug("leaving rewriteQuery with: " + query.toString());
+    }
+    return query;
+  }
+  
+  /**
+   * Evaluates the query against an event.
+   * 
+   * @param eventFields
+   * @return
+   */
+  public boolean evaluate(EventFields eventFields) {
+    
+    this.modifiedQuery = null;
+    boolean rewritten = false;
+    
+    // Copy the query
+    StringBuilder q = new StringBuilder(query);
+    // Copy the literals, we are going to remove elements from this set
+    // when they are added to the JEXL context. This will allow us to
+    // determine which items in the query where *NOT* in the data.
+    HashSet<String> literalsCopy = new HashSet<String>(literals);
+    
+    // Loop through the event fields and add them to the JexlContext.
+    for (Entry<String,Collection<FieldValue>> field : eventFields.asMap().entrySet()) {
+      String fName = field.getKey();
+      if (caseInsensitive) {
+        fName = fName.toLowerCase();
+      }
+      // If this field is not part of the expression, then skip it.
+      if (!literals.contains(fName)) {
+        continue;
+      } else {
+        literalsCopy.remove(fName);
+      }
+      
+      // This field may have multiple values.
+      if (field.getValue().size() == 0) {
+        continue;
+      } else if (field.getValue().size() == 1) {
+        // We are explicitly converting these bytes to a String.
+        if (caseInsensitive) {
+          ctx.set(field.getKey().toLowerCase(), (new String(field.getValue().iterator().next().getValue())).toLowerCase());
         } else {
-            return false;
+          ctx.set(field.getKey(), new String(field.getValue().iterator().next().getValue()));
         }
-    } //End of method
-
-    /**
-     *
-     * @return rewritten query that was evaluated against the most recent event
-     */
-    public String getModifiedQuery() {
-        return this.modifiedQuery;
+        
+      } else {
+        // q = queryRewrite(q, field.getKey(), field.getValue());
+        q = rewriteQuery(q, field.getKey(), field.getValue());
+        rewritten = true;
+      }// End of if
+      
+    }// End of loop
+    
+    // For any literals in the query that were not found in the data, add them to the context
+    // with a null value.
+    for (String lit : literalsCopy) {
+      ctx.set(lit, null);
+    }
+    
+    if (log.isDebugEnabled()) {
+      log.debug("Evaluating query: " + q.toString());
+    }
+    
+    this.modifiedQuery = q.toString();
+    
+    Boolean result = null;
+    if (rewritten) {
+      Script script = engine.createScript(this.modifiedQuery);
+      try {
+        result = (Boolean) script.execute(ctx);
+      } catch (Exception e) {
+        log.error("Error evaluating script: " + this.modifiedQuery + " against event" + eventFields.toString(), e);
+      }
+    } else {
+      Expression expr = engine.createExpression(this.modifiedQuery);
+      try {
+        result = (Boolean) expr.evaluate(ctx);
+      } catch (Exception e) {
+        log.error("Error evaluating expression: " + this.modifiedQuery + " against event" + eventFields.toString(), e);
+      }
+    }
+    if (null != result && result) {
+      return true;
+    } else {
+      return false;
     }
+  } // End of method
+  
+  /**
+   * 
+   * @return rewritten query that was evaluated against the most recent event
+   */
+  public String getModifiedQuery() {
+    return this.modifiedQuery;
+  }
 }

Modified: incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/parser/QueryParser.java
URL: http://svn.apache.org/viewvc/incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/parser/QueryParser.java?rev=1210600&r1=1210599&r2=1210600&view=diff
==============================================================================
--- incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/parser/QueryParser.java (original)
+++ incubator/accumulo/trunk/contrib/accumulo_sample/query/src/main/java/parser/QueryParser.java Mon Dec  5 20:05:49 2011
@@ -1,19 +1,19 @@
 /*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package parser;
 
 import java.io.StringReader;
@@ -80,751 +80,765 @@ import org.apache.hadoop.util.hash.Murmu
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Multimap;
 
-
 /**
- * Parses the query for the purposes of extracting terms, operators, and literals for
- * query optimization. This class does not necessarily understand how to parse all of the
- * possible combinations of the JEXL syntax, but that does not mean that the query will
- * not evaluate against the event objects. It means that the unsupported operators will not
- * be parsed and included in the optimization step.
- *
+ * Parses the query for the purposes of extracting terms, operators, and literals for query optimization. This class does not necessarily understand how to
+ * parse all of the possible combinations of the JEXL syntax, but that does not mean that the query will not evaluate against the event objects. It means that
+ * the unsupported operators will not be parsed and included in the optimization step.
+ * 
  */
 public class QueryParser implements ParserVisitor {
-
-	public static class QueryTerm {
-		private boolean negated = false;
-		private String operator = null;
-		private Object value = null;
-		public QueryTerm(boolean negated, String operator,Object value) {
-			super();
-			this.negated = negated;
-			this.operator = operator;
-			this.value = value;
-		}
-		public boolean isNegated() {
-			return negated;
-		}
-		public String getOperator() {
-			return operator;
-		}
-		public Object getValue() {
-			return value;
-		}
-		public void setNegated(boolean negated) {
-			this.negated = negated;
-		}
-		public void setOperator(String operator) {
-			this.operator = operator;
-		}
-		public void setValue(Object value) {
-			this.value = value;
-		}
-		public String toString() {
-			StringBuilder buf = new StringBuilder();
-			buf.append("negated: ").append(negated).append(", operator: ").append(operator).append(", value: ").append(value);
-			return buf.toString();
-		}
-	}
-
-	/**
-	 * Holder object
-	 */
-	static class ObjectHolder {
-		Object object;
-		public Object getObject() {
-			return object;
-		}
-		public void setObject(Object object) {
-			this.object = object;
-		}
-	}
-
-	static class FunctionResult {
-		private List<TermResult> terms = new ArrayList<TermResult>();
-
-		public List<TermResult> getTerms() {
-			return terms;
-		}
-	}
-
-	/**
-	 * Holder object for a term (i.e. field name)
-	 */
-	static class TermResult {
-		Object value;
-		public TermResult(Object value) { this.value = value; }
-	}
-
-	/**
-	 * Holder object for a literal (integer, float, string, or null literal) value
-	 */
-	static class LiteralResult {
-		Object value;
-		public LiteralResult(Object value) { this.value = value; }
-	}
-
-	/**
-	 * Object used to store context information as the AST is being iterated over.
-	 */
-	static class EvaluationContext {
-		boolean inOrContext = false;
-		boolean inNotContext = false;
-		boolean inAndContext = false;
-	}
-
-	/**
-	 * Object to store information from previously parsed queries.
-	 */
-	private static class CacheEntry {
-		private Set<String> negatedTerms = null;
-		private Set<String> andTerms = null;
-		private Set<String> orTerms = null;
-		private Set<Object> literals = null;
-		private Multimap<String,QueryTerm> terms = null;
-		private ASTJexlScript rootNode = null;
-		private TreeNode tree = null;
-		public CacheEntry(Set<String> negatedTerms, Set<String> andTerms,
-				Set<String> orTerms, Set<Object> literals,
-				Multimap<String, QueryTerm> terms, ASTJexlScript rootNode,
-				TreeNode tree) {
-			super();
-			this.negatedTerms = negatedTerms;
-			this.andTerms = andTerms;
-			this.orTerms = orTerms;
-			this.literals = literals;
-			this.terms = terms;
-			this.rootNode = rootNode;
-			this.tree = tree;
-		}
-		public Set<String> getNegatedTerms() {
-			return negatedTerms;
-		}
-		public Set<String> getAndTerms() {
-			return andTerms;
-		}
-		public Set<String> getOrTerms() {
-			return orTerms;
-		}
-		public Set<Object> getLiterals() {
-			return literals;
-		}
-		public Multimap<String, QueryTerm> getTerms() {
-			return terms;
-		}
-		public ASTJexlScript getRootNode() {
-			return rootNode;
-		}
-		public TreeNode getTree() {
-			return tree;
-		}
-	}
-
-	private static final int SEED = 650567;
-
-	private static LRUMap cache = new LRUMap();
-
-	protected Set<String> negatedTerms = new HashSet<String>();
-
-	private Set<String> andTerms = new HashSet<String>();
-
-	private Set<String> orTerms = new HashSet<String>();
-
-	/**
-	 * List of String, Integer, Float, etc literals that were passed in the query
-	 */
-	private Set<Object> literals = new HashSet<Object>();
-	
-	/**
-	 * Map of terms (field names) to QueryTerm objects.
-	 */
-	private Multimap<String,QueryTerm> terms = HashMultimap.create();
-
-	private ASTJexlScript rootNode = null;
-
-	private TreeNode tree = null;
-
-	private int hashVal = 0;
-	
-	public QueryParser() {
-	}
-	
-	private void reset() {
-		this.negatedTerms.clear();
-		this.andTerms.clear();
-		this.orTerms.clear();
-		this.literals.clear();
-		this.terms = HashMultimap.create();
-	}
-
-	public void execute(String query) throws ParseException {
-		reset();
-        query = query.replaceAll("\\s+AND\\s+", " and ");
-        query = query.replaceAll("\\s+OR\\s+", " or ");
-        query = query.replaceAll("\\s+NOT\\s+", " not ");
-
-		//Check to see if its in the cache
-		Hash hash = MurmurHash.getInstance();
-		this.hashVal = hash.hash(query.getBytes(), SEED);
-		if (cache.containsKey(hashVal)) {
-			CacheEntry entry = (CacheEntry) cache.get(hashVal);
-			this.negatedTerms = entry.getNegatedTerms();
-			this.andTerms = entry.getAndTerms();
-			this.orTerms = entry.getOrTerms();
-			this.literals = entry.getLiterals();
-			this.terms = entry.getTerms();
-			this.rootNode = entry.getRootNode();
-			this.tree = entry.getTree();
-		} else {
-			Parser p = new Parser(new StringReader(";"));
-			rootNode = p.parse(new StringReader(query), null);
-			rootNode.childrenAccept(this, null);
-			TreeBuilder builder = new TreeBuilder(rootNode);
-            tree = builder.getRootNode();
-			CacheEntry entry = new CacheEntry(this.negatedTerms, this.andTerms, this.orTerms, this.literals, this.terms, rootNode, tree);
-			cache.put(hashVal, entry);
-		}
-
-	}
-	
-	public static void clearCache() {
-		cache.clear();
-	}
-	
-	/**
-	 *
-	 * @return this queries hash value
-	 */
-	public int getHashValue() {
-		return this.hashVal;
-	}
-
-	public TreeNode getIteratorTree() {
-		return this.tree;
-	}
-
-	/**
-	 *
-	 * @return JEXL abstract syntax tree
-	 */
-	public ASTJexlScript getAST() {
-		return this.rootNode;
-	}
-
-	/**
-	 *
-	 * @return Set of field names to use in the optimizer for nots. As a general
-	 * rule none of these terms should be used to find an event and should they
-	 * should be evaluated on each event after being found.
-	 */
-	public Set<String> getNegatedTermsForOptimizer() {
-		return negatedTerms;
-	}
-
-	/**
-	 *
-	 * @return Set of field names to use in the optimizer for ands. As a general
-	 * rule any one term of an and clause can be used to find associated events.
-	 */
-	public Set<String> getAndTermsForOptimizer() {
-		return andTerms;
-	}
-
-
-	/**
-	 *
-	 * @return Set of field names to use in the optimizer for ors. As a general rule
-	 * any terms that are part of an or clause need to be searched to find the
-	 * associated events.
-	 */
-	public Set<String> getOrTermsForOptimizer() {
-		return orTerms;
-	}
-
-	/**
-	 *
-	 * @return String, Integer, and Float literals used in the query.
-	 */
-	public Set<Object> getQueryLiterals() {
-		return literals;
-	}
-
-	/**
-	 *
-	 * @return Set of all identifiers (field names) in the query.
-	 */
-	public Set<String> getQueryIdentifiers() {
-		return terms.keySet();
-	}
-
-	/**
-	 *
-	 * @return map of term (field name) to QueryTerm object
-	 */
-	public Multimap<String,QueryTerm> getQueryTerms() {
-		return terms;
-	}
-
-	public Object visit(SimpleNode node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTJexlScript node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTBlock node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTAmbiguous node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTIfStatement node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTWhileStatement node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTForeachStatement node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTAssignment node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTTernaryNode node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTOrNode node, Object data) {
-		boolean previouslyInOrContext = false;
-		EvaluationContext ctx = null;
-		if (null != data && data instanceof EvaluationContext) {
-			ctx = (EvaluationContext) data;
-			previouslyInOrContext = ctx.inOrContext;
-		} else {
-			ctx = new EvaluationContext();
-		}
-		ctx.inOrContext = true;
-		//Process both sides of this node.
-        node.jjtGetChild(0).jjtAccept(this, ctx);
-        node.jjtGetChild(1).jjtAccept(this, ctx);
-        //reset the state
-        if (null != data && !previouslyInOrContext)
-        	ctx.inOrContext = false;
-		return null;
-	}
-
-	public Object visit(ASTAndNode node, Object data) {
-		boolean previouslyInAndContext = false;
-		EvaluationContext ctx = null;
-		if (null != data && data instanceof EvaluationContext) {
-			ctx = (EvaluationContext) data;
-			previouslyInAndContext = ctx.inAndContext;
-		} else {
-			ctx = new EvaluationContext();
-		}
-		ctx.inAndContext = true;
-		//Process both sides of this node.
-        node.jjtGetChild(0).jjtAccept(this, ctx);
-        node.jjtGetChild(1).jjtAccept(this, ctx);
-        //reset the state
-        if (null != data && !previouslyInAndContext)
-        	ctx.inAndContext = false;
-		return null;
-	}
-
-	public Object visit(ASTBitwiseOrNode node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTBitwiseXorNode node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTBitwiseAndNode node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTEQNode node, Object data) {
-		StringBuilder fieldName = new StringBuilder();
-		ObjectHolder value = new ObjectHolder();
-		//Process both sides of this node.
-        Object left = node.jjtGetChild(0).jjtAccept(this, data);
-        Object right = node.jjtGetChild(1).jjtAccept(this, data);
-        //Ignore functions in the query
-        if (left instanceof FunctionResult || right instanceof FunctionResult)
-        	return null;
-        decodeResults(left, right, fieldName, value);
-        //We need to check to see if we are in a NOT context. If so,
-        //then we need to reverse the negation.
-        boolean negated = false;
-        if (null != data && data instanceof EvaluationContext) {
-        	EvaluationContext ctx = (EvaluationContext) data;
-        	if (ctx.inNotContext)
-        		negated = !negated;
-        }
-        QueryTerm term = new QueryTerm(negated, JexlOperatorConstants.getOperator(node.getClass()), value.getObject());
-        terms.put(fieldName.toString(), term);
-		return null;
-	}
-
-	public Object visit(ASTNENode node, Object data) {
-		StringBuilder fieldName = new StringBuilder();
-		ObjectHolder value = new ObjectHolder();
-		//Process both sides of this node.
-        Object left = node.jjtGetChild(0).jjtAccept(this, data);
-        Object right = node.jjtGetChild(1).jjtAccept(this, data);
-        //Ignore functions in the query
-        if (left instanceof FunctionResult || right instanceof FunctionResult)
-        	return null;
-        decodeResults(left, right, fieldName, value);
-        //We need to check to see if we are in a NOT context. If so,
-        //then we need to reverse the negation.
-        boolean negated = true;
-        if (null != data && data instanceof EvaluationContext) {
-        	EvaluationContext ctx = (EvaluationContext) data;
-        	if (ctx.inNotContext)
-        		negated = !negated;
-        }
-        if (negated)
-        	negatedTerms.add(fieldName.toString());
-        QueryTerm term = new QueryTerm(negated, JexlOperatorConstants.getOperator(node.getClass()), value.getObject());
-        terms.put(fieldName.toString(), term);
-		return null;
-	}
-
-	public Object visit(ASTLTNode node, Object data) {
-		StringBuilder fieldName = new StringBuilder();
-		ObjectHolder value = new ObjectHolder();
-		//Process both sides of this node.
-        Object left = node.jjtGetChild(0).jjtAccept(this, data);
-        Object right = node.jjtGetChild(1).jjtAccept(this, data);
-        //Ignore functions in the query
-        if (left instanceof FunctionResult || right instanceof FunctionResult)
-        	return null;
-        decodeResults(left, right, fieldName, value);
-        //We need to check to see if we are in a NOT context. If so,
-        //then we need to reverse the negation.
-        boolean negated = false;
-        if (null != data && data instanceof EvaluationContext) {
-        	EvaluationContext ctx = (EvaluationContext) data;
-        	if (ctx.inNotContext)
-        		negated = !negated;
-        }
-        QueryTerm term = new QueryTerm(negated, JexlOperatorConstants.getOperator(node.getClass()), value.getObject());
-        terms.put(fieldName.toString(), term);
-		return null;
-	}
-
-	public Object visit(ASTGTNode node, Object data) {
-		StringBuilder fieldName = new StringBuilder();
-		ObjectHolder value = new ObjectHolder();
-		//Process both sides of this node.
-        Object left = node.jjtGetChild(0).jjtAccept(this, data);
-        Object right = node.jjtGetChild(1).jjtAccept(this, data);
-        //Ignore functions in the query
-        if (left instanceof FunctionResult || right instanceof FunctionResult)
-        	return null;
-        decodeResults(left, right, fieldName, value);
-        //We need to check to see if we are in a NOT context. If so,
-        //then we need to reverse the negation.
-        boolean negated = false;
-        if (null != data && data instanceof EvaluationContext) {
-        	EvaluationContext ctx = (EvaluationContext) data;
-        	if (ctx.inNotContext)
-        		negated = !negated;
-        }
-        QueryTerm term = new QueryTerm(negated, JexlOperatorConstants.getOperator(node.getClass()), value.getObject());
-        terms.put(fieldName.toString(), term);
-		return null;
-	}
-
-	public Object visit(ASTLENode node, Object data) {
-		StringBuilder fieldName = new StringBuilder();
-		ObjectHolder value = new ObjectHolder();
-		//Process both sides of this node.
-        Object left = node.jjtGetChild(0).jjtAccept(this, data);
-        Object right = node.jjtGetChild(1).jjtAccept(this, data);
-        //Ignore functions in the query
-        if (left instanceof FunctionResult || right instanceof FunctionResult)
-        	return null;
-        decodeResults(left, right, fieldName, value);
-        //We need to check to see if we are in a NOT context. If so,
-        //then we need to reverse the negation.
-        boolean negated = false;
-        if (null != data && data instanceof EvaluationContext) {
-        	EvaluationContext ctx = (EvaluationContext) data;
-        	if (ctx.inNotContext)
-        		negated = !negated;
-        }
-        QueryTerm term = new QueryTerm(negated, JexlOperatorConstants.getOperator(node.getClass()), value.getObject());
-        terms.put(fieldName.toString(), term);
-		return null;
-	}
-
-	public Object visit(ASTGENode node, Object data) {
-		StringBuilder fieldName = new StringBuilder();
-		ObjectHolder value = new ObjectHolder();
-		//Process both sides of this node.
-        Object left = node.jjtGetChild(0).jjtAccept(this, data);
-        Object right = node.jjtGetChild(1).jjtAccept(this, data);
-        //Ignore functions in the query
-        if (left instanceof FunctionResult || right instanceof FunctionResult)
-        	return null;
-        decodeResults(left, right, fieldName, value);
-        //We need to check to see if we are in a NOT context. If so,
-        //then we need to reverse the negation.
-        boolean negated = false;
-        if (null != data && data instanceof EvaluationContext) {
-        	EvaluationContext ctx = (EvaluationContext) data;
-        	if (ctx.inNotContext)
-        		negated = !negated;
-        }
-        QueryTerm term = new QueryTerm(negated, JexlOperatorConstants.getOperator(node.getClass()), value.getObject());
-        terms.put(fieldName.toString(), term);
-		return null;
-	}
-
-	public Object visit(ASTERNode node, Object data) {
-		StringBuilder fieldName = new StringBuilder();
-		ObjectHolder value = new ObjectHolder();
-		//Process both sides of this node.
-        Object left = node.jjtGetChild(0).jjtAccept(this, data);
-        Object right = node.jjtGetChild(1).jjtAccept(this, data);
-        //Ignore functions in the query
-        if (left instanceof FunctionResult || right instanceof FunctionResult)
-        	return null;
-        decodeResults(left, right, fieldName, value);
-        //We need to check to see if we are in a NOT context. If so,
-        //then we need to reverse the negation.
-        boolean negated = false;
-        if (null != data && data instanceof EvaluationContext) {
-        	EvaluationContext ctx = (EvaluationContext) data;
-        	if (ctx.inNotContext)
-        		negated = !negated;
-        }
-        QueryTerm term = new QueryTerm(negated, JexlOperatorConstants.getOperator(node.getClass()), value.getObject());
-        terms.put(fieldName.toString(), term);
-		return null;
-	}
-
-	public Object visit(ASTNRNode node, Object data) {
-		StringBuilder fieldName = new StringBuilder();
-		ObjectHolder value = new ObjectHolder();
-		//Process both sides of this node.
-        Object left = node.jjtGetChild(0).jjtAccept(this, data);
-        Object right = node.jjtGetChild(1).jjtAccept(this, data);
-        //Ignore functions in the query
-        if (left instanceof FunctionResult || right instanceof FunctionResult)
-        	return null;
-        decodeResults(left, right, fieldName, value);
-        //We need to check to see if we are in a NOT context. If so,
-        //then we need to reverse the negation.
-        boolean negated = true;
-        if (null != data && data instanceof EvaluationContext) {
-        	EvaluationContext ctx = (EvaluationContext) data;
-        	if (ctx.inNotContext)
-        		negated = !negated;
-        }
-        if (negated)
-        	negatedTerms.add(fieldName.toString());
-        QueryTerm term = new QueryTerm(negated, JexlOperatorConstants.getOperator(node.getClass()), value.getObject());
-        terms.put(fieldName.toString(), term);
-		return null;
-	}
-
-	public Object visit(ASTAdditiveNode node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTAdditiveOperator node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTMulNode node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTDivNode node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTModNode node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTUnaryMinusNode node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTBitwiseComplNode node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTNotNode node, Object data) {
-		boolean previouslyInNotContext = false;
-		EvaluationContext ctx = null;
-		if (null != data && data instanceof EvaluationContext) {
-			ctx = (EvaluationContext) data;
-			previouslyInNotContext = ctx.inNotContext;
-		} else {
-			ctx = new EvaluationContext();
-		}
-		ctx.inNotContext = true;
-		//Process both sides of this node.
-        node.jjtGetChild(0).jjtAccept(this, ctx);
-        //reset the state
-        if (null != data && !previouslyInNotContext)
-        	ctx.inNotContext = false;
-		return null;
-	}
-
-	public Object visit(ASTIdentifier node, Object data) {
-		if (data instanceof EvaluationContext) {
-			EvaluationContext ctx = (EvaluationContext) data;
-			if (ctx.inAndContext)
-				andTerms.add(node.image);
-			if (ctx.inNotContext)
-				negatedTerms.add(node.image);
-			if (ctx.inOrContext)
-				orTerms.add(node.image);
-		}
-		return new TermResult(node.image);
-	}
-
-	public Object visit(ASTNullLiteral node, Object data) {
-        literals.add(node.image);
-		return new LiteralResult(node.image);
-	}
-
-	public Object visit(ASTTrueNode node, Object data) {
-		return new LiteralResult(node.image);
-	}
-
-	public Object visit(ASTFalseNode node, Object data) {
-		return new LiteralResult(node.image);
-	}
-
-	public Object visit(ASTIntegerLiteral node, Object data) {
-        literals.add(node.image);
-		return new LiteralResult(node.image);
-	}
-
-	public Object visit(ASTFloatLiteral node, Object data) {
-        literals.add(node.image);
-		return new LiteralResult(node.image);
-	}
-
-	public Object visit(ASTStringLiteral node, Object data) {
-        literals.add("'"+node.image+"'");
-		return new LiteralResult("'"+node.image+"'");
-	}
-
-	public Object visit(ASTArrayLiteral node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTMapLiteral node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTMapEntry node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTEmptyFunction node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTSizeFunction node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTFunctionNode node, Object data) {
-        //We need to check to see if we are in a NOT context. If so,
-        //then we need to reverse the negation.
-        boolean negated = true;
-        if (null != data && data instanceof EvaluationContext) {
-        	EvaluationContext ctx = (EvaluationContext) data;
-        	if (ctx.inNotContext)
-        		negated = !negated;
-        }
-        //used to rebuild function call from the AST
-        StringBuilder buf = new StringBuilder();
-        String sep = "";
-        // objectNode 0 is the prefix
-        buf.append(node.jjtGetChild(0).image).append(":");
-        // objectNode 1 is the identifier , the others are parameters.
-        buf.append(node.jjtGetChild(1).image).append("(");
-        // process the remaining arguments
-		FunctionResult fr = new FunctionResult();
-        int argc = node.jjtGetNumChildren() - 2;
-        for (int i = 0; i < argc; i++) {
-    		//Process both sides of this node.
-            Object result = node.jjtGetChild(i + 2).jjtAccept(this, data);
-            if (result instanceof TermResult) {
-            	TermResult tr = (TermResult) result;
-            	fr.getTerms().add(tr);
-            	buf.append(sep).append(tr.value);
-            	sep = ", ";            	
-            } else {
-            	buf.append(sep).append(node.jjtGetChild(i + 2).image);
-            	sep = ", ";            	
-            }
-        }
-        buf.append(")");
-        //Capture the entire function call for each function parameter
-        for (TermResult tr : fr.terms)
-        	terms.put((String) tr.value, new QueryTerm(negated, JexlOperatorConstants.getOperator(node.getClass()), buf.toString()));
-        return fr;
-	}
-
-	public Object visit(ASTMethodNode node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTSizeMethod node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTConstructorNode node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTArrayAccess node, Object data) {
-		return null;
-	}
-
-	public Object visit(ASTReference node, Object data) {
-        return node.jjtGetChild(0).jjtAccept(this, data);
-	}
-
-	protected void decodeResults(Object left, Object right, StringBuilder fieldName, ObjectHolder holder) {
-		if (left instanceof TermResult) {
-			TermResult tr = (TermResult) left;
-			fieldName.append((String) tr.value);
-			//Then the right has to be the value
-			if (right instanceof LiteralResult) {
-				holder.setObject(((LiteralResult) right).value);
-			} else {
-				throw new IllegalArgumentException("Object mismatch");
-			}
-		} else if (right instanceof TermResult) {
-			TermResult tr = (TermResult) right;
-			fieldName.append((String) tr.value);
-			if (left instanceof LiteralResult) {
-				holder.setObject(((LiteralResult) left).value);
-			} else {
-				throw new IllegalArgumentException("Object mismatch");
-			}
-
-		} else {
-			throw new IllegalArgumentException("No Term specified in query");
-		}
-	}
+  
+  public static class QueryTerm {
+    private boolean negated = false;
+    private String operator = null;
+    private Object value = null;
+    
+    public QueryTerm(boolean negated, String operator, Object value) {
+      super();
+      this.negated = negated;
+      this.operator = operator;
+      this.value = value;
+    }
+    
+    public boolean isNegated() {
+      return negated;
+    }
+    
+    public String getOperator() {
+      return operator;
+    }
+    
+    public Object getValue() {
+      return value;
+    }
+    
+    public void setNegated(boolean negated) {
+      this.negated = negated;
+    }
+    
+    public void setOperator(String operator) {
+      this.operator = operator;
+    }
+    
+    public void setValue(Object value) {
+      this.value = value;
+    }
+    
+    public String toString() {
+      StringBuilder buf = new StringBuilder();
+      buf.append("negated: ").append(negated).append(", operator: ").append(operator).append(", value: ").append(value);
+      return buf.toString();
+    }
+  }
+  
+  /**
+   * Holder object
+   */
+  static class ObjectHolder {
+    Object object;
+    
+    public Object getObject() {
+      return object;
+    }
+    
+    public void setObject(Object object) {
+      this.object = object;
+    }
+  }
+  
+  static class FunctionResult {
+    private List<TermResult> terms = new ArrayList<TermResult>();
+    
+    public List<TermResult> getTerms() {
+      return terms;
+    }
+  }
+  
+  /**
+   * Holder object for a term (i.e. field name)
+   */
+  static class TermResult {
+    Object value;
+    
+    public TermResult(Object value) {
+      this.value = value;
+    }
+  }
+  
+  /**
+   * Holder object for a literal (integer, float, string, or null literal) value
+   */
+  static class LiteralResult {
+    Object value;
+    
+    public LiteralResult(Object value) {
+      this.value = value;
+    }
+  }
+  
+  /**
+   * Object used to store context information as the AST is being iterated over.
+   */
+  static class EvaluationContext {
+    boolean inOrContext = false;
+    boolean inNotContext = false;
+    boolean inAndContext = false;
+  }
+  
+  /**
+   * Object to store information from previously parsed queries.
+   */
+  private static class CacheEntry {
+    private Set<String> negatedTerms = null;
+    private Set<String> andTerms = null;
+    private Set<String> orTerms = null;
+    private Set<Object> literals = null;
+    private Multimap<String,QueryTerm> terms = null;
+    private ASTJexlScript rootNode = null;
+    private TreeNode tree = null;
+    
+    public CacheEntry(Set<String> negatedTerms, Set<String> andTerms, Set<String> orTerms, Set<Object> literals, Multimap<String,QueryTerm> terms,
+        ASTJexlScript rootNode, TreeNode tree) {
+      super();
+      this.negatedTerms = negatedTerms;
+      this.andTerms = andTerms;
+      this.orTerms = orTerms;
+      this.literals = literals;
+      this.terms = terms;
+      this.rootNode = rootNode;
+      this.tree = tree;
+    }
+    
+    public Set<String> getNegatedTerms() {
+      return negatedTerms;
+    }
+    
+    public Set<String> getAndTerms() {
+      return andTerms;
+    }
+    
+    public Set<String> getOrTerms() {
+      return orTerms;
+    }
+    
+    public Set<Object> getLiterals() {
+      return literals;
+    }
+    
+    public Multimap<String,QueryTerm> getTerms() {
+      return terms;
+    }
+    
+    public ASTJexlScript getRootNode() {
+      return rootNode;
+    }
+    
+    public TreeNode getTree() {
+      return tree;
+    }
+  }
+  
+  private static final int SEED = 650567;
+  
+  private static LRUMap cache = new LRUMap();
+  
+  protected Set<String> negatedTerms = new HashSet<String>();
+  
+  private Set<String> andTerms = new HashSet<String>();
+  
+  private Set<String> orTerms = new HashSet<String>();
+  
+  /**
+   * List of String, Integer, Float, etc literals that were passed in the query
+   */
+  private Set<Object> literals = new HashSet<Object>();
+  
+  /**
+   * Map of terms (field names) to QueryTerm objects.
+   */
+  private Multimap<String,QueryTerm> terms = HashMultimap.create();
+  
+  private ASTJexlScript rootNode = null;
+  
+  private TreeNode tree = null;
+  
+  private int hashVal = 0;
+  
+  public QueryParser() {}
+  
+  private void reset() {
+    this.negatedTerms.clear();
+    this.andTerms.clear();
+    this.orTerms.clear();
+    this.literals.clear();
+    this.terms = HashMultimap.create();
+  }
+  
+  public void execute(String query) throws ParseException {
+    reset();
+    query = query.replaceAll("\\s+AND\\s+", " and ");
+    query = query.replaceAll("\\s+OR\\s+", " or ");
+    query = query.replaceAll("\\s+NOT\\s+", " not ");
+    
+    // Check to see if its in the cache
+    Hash hash = MurmurHash.getInstance();
+    this.hashVal = hash.hash(query.getBytes(), SEED);
+    if (cache.containsKey(hashVal)) {
+      CacheEntry entry = (CacheEntry) cache.get(hashVal);
+      this.negatedTerms = entry.getNegatedTerms();
+      this.andTerms = entry.getAndTerms();
+      this.orTerms = entry.getOrTerms();
+      this.literals = entry.getLiterals();
+      this.terms = entry.getTerms();
+      this.rootNode = entry.getRootNode();
+      this.tree = entry.getTree();
+    } else {
+      Parser p = new Parser(new StringReader(";"));
+      rootNode = p.parse(new StringReader(query), null);
+      rootNode.childrenAccept(this, null);
+      TreeBuilder builder = new TreeBuilder(rootNode);
+      tree = builder.getRootNode();
+      CacheEntry entry = new CacheEntry(this.negatedTerms, this.andTerms, this.orTerms, this.literals, this.terms, rootNode, tree);
+      cache.put(hashVal, entry);
+    }
+    
+  }
+  
+  public static void clearCache() {
+    cache.clear();
+  }
+  
+  /**
+   * 
+   * @return this queries hash value
+   */
+  public int getHashValue() {
+    return this.hashVal;
+  }
+  
+  public TreeNode getIteratorTree() {
+    return this.tree;
+  }
+  
+  /**
+   * 
+   * @return JEXL abstract syntax tree
+   */
+  public ASTJexlScript getAST() {
+    return this.rootNode;
+  }
+  
+  /**
+   * 
+   * @return Set of field names to use in the optimizer for nots. As a general rule none of these terms should be used to find an event and should they should
+   *         be evaluated on each event after being found.
+   */
+  public Set<String> getNegatedTermsForOptimizer() {
+    return negatedTerms;
+  }
+  
+  /**
+   * 
+   * @return Set of field names to use in the optimizer for ands. As a general rule any one term of an and clause can be used to find associated events.
+   */
+  public Set<String> getAndTermsForOptimizer() {
+    return andTerms;
+  }
+  
+  /**
+   * 
+   * @return Set of field names to use in the optimizer for ors. As a general rule any terms that are part of an or clause need to be searched to find the
+   *         associated events.
+   */
+  public Set<String> getOrTermsForOptimizer() {
+    return orTerms;
+  }
+  
+  /**
+   * 
+   * @return String, Integer, and Float literals used in the query.
+   */
+  public Set<Object> getQueryLiterals() {
+    return literals;
+  }
+  
+  /**
+   * 
+   * @return Set of all identifiers (field names) in the query.
+   */
+  public Set<String> getQueryIdentifiers() {
+    return terms.keySet();
+  }
+  
+  /**
+   * 
+   * @return map of term (field name) to QueryTerm object
+   */
+  public Multimap<String,QueryTerm> getQueryTerms() {
+    return terms;
+  }
+  
+  public Object visit(SimpleNode node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTJexlScript node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTBlock node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTAmbiguous node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTIfStatement node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTWhileStatement node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTForeachStatement node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTAssignment node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTTernaryNode node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTOrNode node, Object data) {
+    boolean previouslyInOrContext = false;
+    EvaluationContext ctx = null;
+    if (null != data && data instanceof EvaluationContext) {
+      ctx = (EvaluationContext) data;
+      previouslyInOrContext = ctx.inOrContext;
+    } else {
+      ctx = new EvaluationContext();
+    }
+    ctx.inOrContext = true;
+    // Process both sides of this node.
+    node.jjtGetChild(0).jjtAccept(this, ctx);
+    node.jjtGetChild(1).jjtAccept(this, ctx);
+    // reset the state
+    if (null != data && !previouslyInOrContext)
+      ctx.inOrContext = false;
+    return null;
+  }
+  
+  public Object visit(ASTAndNode node, Object data) {
+    boolean previouslyInAndContext = false;
+    EvaluationContext ctx = null;
+    if (null != data && data instanceof EvaluationContext) {
+      ctx = (EvaluationContext) data;
+      previouslyInAndContext = ctx.inAndContext;
+    } else {
+      ctx = new EvaluationContext();
+    }
+    ctx.inAndContext = true;
+    // Process both sides of this node.
+    node.jjtGetChild(0).jjtAccept(this, ctx);
+    node.jjtGetChild(1).jjtAccept(this, ctx);
+    // reset the state
+    if (null != data && !previouslyInAndContext)
+      ctx.inAndContext = false;
+    return null;
+  }
+  
+  public Object visit(ASTBitwiseOrNode node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTBitwiseXorNode node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTBitwiseAndNode node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTEQNode node, Object data) {
+    StringBuilder fieldName = new StringBuilder();
+    ObjectHolder value = new ObjectHolder();
+    // Process both sides of this node.
+    Object left = node.jjtGetChild(0).jjtAccept(this, data);
+    Object right = node.jjtGetChild(1).jjtAccept(this, data);
+    // Ignore functions in the query
+    if (left instanceof FunctionResult || right instanceof FunctionResult)
+      return null;
+    decodeResults(left, right, fieldName, value);
+    // We need to check to see if we are in a NOT context. If so,
+    // then we need to reverse the negation.
+    boolean negated = false;
+    if (null != data && data instanceof EvaluationContext) {
+      EvaluationContext ctx = (EvaluationContext) data;
+      if (ctx.inNotContext)
+        negated = !negated;
+    }
+    QueryTerm term = new QueryTerm(negated, JexlOperatorConstants.getOperator(node.getClass()), value.getObject());
+    terms.put(fieldName.toString(), term);
+    return null;
+  }
+  
+  public Object visit(ASTNENode node, Object data) {
+    StringBuilder fieldName = new StringBuilder();
+    ObjectHolder value = new ObjectHolder();
+    // Process both sides of this node.
+    Object left = node.jjtGetChild(0).jjtAccept(this, data);
+    Object right = node.jjtGetChild(1).jjtAccept(this, data);
+    // Ignore functions in the query
+    if (left instanceof FunctionResult || right instanceof FunctionResult)
+      return null;
+    decodeResults(left, right, fieldName, value);
+    // We need to check to see if we are in a NOT context. If so,
+    // then we need to reverse the negation.
+    boolean negated = true;
+    if (null != data && data instanceof EvaluationContext) {
+      EvaluationContext ctx = (EvaluationContext) data;
+      if (ctx.inNotContext)
+        negated = !negated;
+    }
+    if (negated)
+      negatedTerms.add(fieldName.toString());
+    QueryTerm term = new QueryTerm(negated, JexlOperatorConstants.getOperator(node.getClass()), value.getObject());
+    terms.put(fieldName.toString(), term);
+    return null;
+  }
+  
+  public Object visit(ASTLTNode node, Object data) {
+    StringBuilder fieldName = new StringBuilder();
+    ObjectHolder value = new ObjectHolder();
+    // Process both sides of this node.
+    Object left = node.jjtGetChild(0).jjtAccept(this, data);
+    Object right = node.jjtGetChild(1).jjtAccept(this, data);
+    // Ignore functions in the query
+    if (left instanceof FunctionResult || right instanceof FunctionResult)
+      return null;
+    decodeResults(left, right, fieldName, value);
+    // We need to check to see if we are in a NOT context. If so,
+    // then we need to reverse the negation.
+    boolean negated = false;
+    if (null != data && data instanceof EvaluationContext) {
+      EvaluationContext ctx = (EvaluationContext) data;
+      if (ctx.inNotContext)
+        negated = !negated;
+    }
+    QueryTerm term = new QueryTerm(negated, JexlOperatorConstants.getOperator(node.getClass()), value.getObject());
+    terms.put(fieldName.toString(), term);
+    return null;
+  }
+  
+  public Object visit(ASTGTNode node, Object data) {
+    StringBuilder fieldName = new StringBuilder();
+    ObjectHolder value = new ObjectHolder();
+    // Process both sides of this node.
+    Object left = node.jjtGetChild(0).jjtAccept(this, data);
+    Object right = node.jjtGetChild(1).jjtAccept(this, data);
+    // Ignore functions in the query
+    if (left instanceof FunctionResult || right instanceof FunctionResult)
+      return null;
+    decodeResults(left, right, fieldName, value);
+    // We need to check to see if we are in a NOT context. If so,
+    // then we need to reverse the negation.
+    boolean negated = false;
+    if (null != data && data instanceof EvaluationContext) {
+      EvaluationContext ctx = (EvaluationContext) data;
+      if (ctx.inNotContext)
+        negated = !negated;
+    }
+    QueryTerm term = new QueryTerm(negated, JexlOperatorConstants.getOperator(node.getClass()), value.getObject());
+    terms.put(fieldName.toString(), term);
+    return null;
+  }
+  
+  public Object visit(ASTLENode node, Object data) {
+    StringBuilder fieldName = new StringBuilder();
+    ObjectHolder value = new ObjectHolder();
+    // Process both sides of this node.
+    Object left = node.jjtGetChild(0).jjtAccept(this, data);
+    Object right = node.jjtGetChild(1).jjtAccept(this, data);
+    // Ignore functions in the query
+    if (left instanceof FunctionResult || right instanceof FunctionResult)
+      return null;
+    decodeResults(left, right, fieldName, value);
+    // We need to check to see if we are in a NOT context. If so,
+    // then we need to reverse the negation.
+    boolean negated = false;
+    if (null != data && data instanceof EvaluationContext) {
+      EvaluationContext ctx = (EvaluationContext) data;
+      if (ctx.inNotContext)
+        negated = !negated;
+    }
+    QueryTerm term = new QueryTerm(negated, JexlOperatorConstants.getOperator(node.getClass()), value.getObject());
+    terms.put(fieldName.toString(), term);
+    return null;
+  }
+  
+  public Object visit(ASTGENode node, Object data) {
+    StringBuilder fieldName = new StringBuilder();
+    ObjectHolder value = new ObjectHolder();
+    // Process both sides of this node.
+    Object left = node.jjtGetChild(0).jjtAccept(this, data);
+    Object right = node.jjtGetChild(1).jjtAccept(this, data);
+    // Ignore functions in the query
+    if (left instanceof FunctionResult || right instanceof FunctionResult)
+      return null;
+    decodeResults(left, right, fieldName, value);
+    // We need to check to see if we are in a NOT context. If so,
+    // then we need to reverse the negation.
+    boolean negated = false;
+    if (null != data && data instanceof EvaluationContext) {
+      EvaluationContext ctx = (EvaluationContext) data;
+      if (ctx.inNotContext)
+        negated = !negated;
+    }
+    QueryTerm term = new QueryTerm(negated, JexlOperatorConstants.getOperator(node.getClass()), value.getObject());
+    terms.put(fieldName.toString(), term);
+    return null;
+  }
+  
+  public Object visit(ASTERNode node, Object data) {
+    StringBuilder fieldName = new StringBuilder();
+    ObjectHolder value = new ObjectHolder();
+    // Process both sides of this node.
+    Object left = node.jjtGetChild(0).jjtAccept(this, data);
+    Object right = node.jjtGetChild(1).jjtAccept(this, data);
+    // Ignore functions in the query
+    if (left instanceof FunctionResult || right instanceof FunctionResult)
+      return null;
+    decodeResults(left, right, fieldName, value);
+    // We need to check to see if we are in a NOT context. If so,
+    // then we need to reverse the negation.
+    boolean negated = false;
+    if (null != data && data instanceof EvaluationContext) {
+      EvaluationContext ctx = (EvaluationContext) data;
+      if (ctx.inNotContext)
+        negated = !negated;
+    }
+    QueryTerm term = new QueryTerm(negated, JexlOperatorConstants.getOperator(node.getClass()), value.getObject());
+    terms.put(fieldName.toString(), term);
+    return null;
+  }
+  
+  public Object visit(ASTNRNode node, Object data) {
+    StringBuilder fieldName = new StringBuilder();
+    ObjectHolder value = new ObjectHolder();
+    // Process both sides of this node.
+    Object left = node.jjtGetChild(0).jjtAccept(this, data);
+    Object right = node.jjtGetChild(1).jjtAccept(this, data);
+    // Ignore functions in the query
+    if (left instanceof FunctionResult || right instanceof FunctionResult)
+      return null;
+    decodeResults(left, right, fieldName, value);
+    // We need to check to see if we are in a NOT context. If so,
+    // then we need to reverse the negation.
+    boolean negated = true;
+    if (null != data && data instanceof EvaluationContext) {
+      EvaluationContext ctx = (EvaluationContext) data;
+      if (ctx.inNotContext)
+        negated = !negated;
+    }
+    if (negated)
+      negatedTerms.add(fieldName.toString());
+    QueryTerm term = new QueryTerm(negated, JexlOperatorConstants.getOperator(node.getClass()), value.getObject());
+    terms.put(fieldName.toString(), term);
+    return null;
+  }
+  
+  public Object visit(ASTAdditiveNode node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTAdditiveOperator node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTMulNode node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTDivNode node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTModNode node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTUnaryMinusNode node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTBitwiseComplNode node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTNotNode node, Object data) {
+    boolean previouslyInNotContext = false;
+    EvaluationContext ctx = null;
+    if (null != data && data instanceof EvaluationContext) {
+      ctx = (EvaluationContext) data;
+      previouslyInNotContext = ctx.inNotContext;
+    } else {
+      ctx = new EvaluationContext();
+    }
+    ctx.inNotContext = true;
+    // Process both sides of this node.
+    node.jjtGetChild(0).jjtAccept(this, ctx);
+    // reset the state
+    if (null != data && !previouslyInNotContext)
+      ctx.inNotContext = false;
+    return null;
+  }
+  
+  public Object visit(ASTIdentifier node, Object data) {
+    if (data instanceof EvaluationContext) {
+      EvaluationContext ctx = (EvaluationContext) data;
+      if (ctx.inAndContext)
+        andTerms.add(node.image);
+      if (ctx.inNotContext)
+        negatedTerms.add(node.image);
+      if (ctx.inOrContext)
+        orTerms.add(node.image);
+    }
+    return new TermResult(node.image);
+  }
+  
+  public Object visit(ASTNullLiteral node, Object data) {
+    literals.add(node.image);
+    return new LiteralResult(node.image);
+  }
+  
+  public Object visit(ASTTrueNode node, Object data) {
+    return new LiteralResult(node.image);
+  }
+  
+  public Object visit(ASTFalseNode node, Object data) {
+    return new LiteralResult(node.image);
+  }
+  
+  public Object visit(ASTIntegerLiteral node, Object data) {
+    literals.add(node.image);
+    return new LiteralResult(node.image);
+  }
+  
+  public Object visit(ASTFloatLiteral node, Object data) {
+    literals.add(node.image);
+    return new LiteralResult(node.image);
+  }
+  
+  public Object visit(ASTStringLiteral node, Object data) {
+    literals.add("'" + node.image + "'");
+    return new LiteralResult("'" + node.image + "'");
+  }
+  
+  public Object visit(ASTArrayLiteral node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTMapLiteral node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTMapEntry node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTEmptyFunction node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTSizeFunction node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTFunctionNode node, Object data) {
+    // We need to check to see if we are in a NOT context. If so,
+    // then we need to reverse the negation.
+    boolean negated = true;
+    if (null != data && data instanceof EvaluationContext) {
+      EvaluationContext ctx = (EvaluationContext) data;
+      if (ctx.inNotContext)
+        negated = !negated;
+    }
+    // used to rebuild function call from the AST
+    StringBuilder buf = new StringBuilder();
+    String sep = "";
+    // objectNode 0 is the prefix
+    buf.append(node.jjtGetChild(0).image).append(":");
+    // objectNode 1 is the identifier , the others are parameters.
+    buf.append(node.jjtGetChild(1).image).append("(");
+    // process the remaining arguments
+    FunctionResult fr = new FunctionResult();
+    int argc = node.jjtGetNumChildren() - 2;
+    for (int i = 0; i < argc; i++) {
+      // Process both sides of this node.
+      Object result = node.jjtGetChild(i + 2).jjtAccept(this, data);
+      if (result instanceof TermResult) {
+        TermResult tr = (TermResult) result;
+        fr.getTerms().add(tr);
+        buf.append(sep).append(tr.value);
+        sep = ", ";
+      } else {
+        buf.append(sep).append(node.jjtGetChild(i + 2).image);
+        sep = ", ";
+      }
+    }
+    buf.append(")");
+    // Capture the entire function call for each function parameter
+    for (TermResult tr : fr.terms)
+      terms.put((String) tr.value, new QueryTerm(negated, JexlOperatorConstants.getOperator(node.getClass()), buf.toString()));
+    return fr;
+  }
+  
+  public Object visit(ASTMethodNode node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTSizeMethod node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTConstructorNode node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTArrayAccess node, Object data) {
+    return null;
+  }
+  
+  public Object visit(ASTReference node, Object data) {
+    return node.jjtGetChild(0).jjtAccept(this, data);
+  }
+  
+  protected void decodeResults(Object left, Object right, StringBuilder fieldName, ObjectHolder holder) {
+    if (left instanceof TermResult) {
+      TermResult tr = (TermResult) left;
+      fieldName.append((String) tr.value);
+      // Then the right has to be the value
+      if (right instanceof LiteralResult) {
+        holder.setObject(((LiteralResult) right).value);
+      } else {
+        throw new IllegalArgumentException("Object mismatch");
+      }
+    } else if (right instanceof TermResult) {
+      TermResult tr = (TermResult) right;
+      fieldName.append((String) tr.value);
+      if (left instanceof LiteralResult) {
+        holder.setObject(((LiteralResult) left).value);
+      } else {
+        throw new IllegalArgumentException("Object mismatch");
+      }
+      
+    } else {
+      throw new IllegalArgumentException("No Term specified in query");
+    }
+  }
 }