Jelajahi Sumber

AMBARI-9153. Allow a set of property names to ignore to be passed into the predicate compiler

John Speidel 10 tahun lalu
induk
melakukan
265f13f467

+ 15 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/predicate/PredicateCompiler.java

@@ -20,6 +20,8 @@ package org.apache.ambari.server.api.predicate;
 
 import org.apache.ambari.server.controller.spi.Predicate;
 
+import java.util.Set;
+
 /**
  * Compiler which takes a query expression as input and produces a predicate instance as output.
  */
@@ -46,4 +48,17 @@ public class PredicateCompiler {
   public Predicate compile(String exp) throws InvalidQueryException {
     return parser.parse(lexer.tokens(exp));
   }
+
+  /**
+   * Generate a predicate from a query expression.
+   *
+   * @param exp               query expression
+   * @param ignoredProperties  set of property names to ignore
+   *
+   * @return a predicate instance
+   * @throws InvalidQueryException if unable to compile the expression
+   */
+  public Predicate compile(String exp, Set<String> ignoredProperties) throws InvalidQueryException {
+    return parser.parse(lexer.tokens(exp, ignoredProperties));
+  }
 }

+ 42 - 2
ambari-server/src/main/java/org/apache/ambari/server/api/predicate/QueryLexer.java

@@ -58,7 +58,7 @@ public class QueryLexer {
       new HashMap<Token.TYPE, List<TokenHandler>>();
 
   /**
-   * Set of property names to ignore.
+   * Static set of property names to ignore.
    */
   private static final Set<String> SET_IGNORE = new HashSet<String>();
 
@@ -108,8 +108,23 @@ public class QueryLexer {
    * @throws InvalidQueryException if the query is invalid
    */
   public Token[] tokens(String exp) throws InvalidQueryException {
+    return tokens(exp, Collections.<String>emptySet());
+  }
 
+  /**
+   * Scan the provided query and generate a token stream to be used by the query parser.
+   *
+   * @param exp               the query expression to scan
+   * @param ignoreProperties  property names which should be ignored
+   *
+   * @return an array of tokens
+   * @throws InvalidQueryException if the query is invalid
+   */
+  public Token[] tokens(String exp, Set<String> ignoreProperties) throws InvalidQueryException {
     ScanContext ctx = new ScanContext();
+    ctx.addPropertiesToIgnore(SET_IGNORE);
+    ctx.addPropertiesToIgnore(ignoreProperties);
+
     for (String tok : parseStringTokens(exp)) {
       List<TokenHandler> listHandlers = TOKEN_HANDLERS.get(ctx.getLastTokenType());
       boolean            processed    = false;
@@ -213,6 +228,11 @@ public class QueryLexer {
      */
     private Token.TYPE m_ignoreSegmentEndToken = null;
 
+    /**
+     * Property names which are to be ignored.
+     */
+    private Set<String> m_propertiesToIgnore = new HashSet<String>();
+
     /**
      * Constructor.
      */
@@ -289,6 +309,26 @@ public class QueryLexer {
     public List<Token> getTokenList() {
       return m_listTokens;
     }
+
+    /**
+     * Get the set of property names that are to be ignored.
+     *
+     * @return set of property names to ignore
+     */
+    public Set<String> getPropertiesToIgnore() {
+      return m_propertiesToIgnore;
+    }
+
+    /**
+     * Add property names to the set of property names to ignore.
+     *
+     * @param ignoredProperties set of property names to ignore
+     */
+    public void addPropertiesToIgnore(Set<String> ignoredProperties) {
+      if (ignoredProperties != null) {
+        m_propertiesToIgnore.addAll(ignoredProperties);
+      }
+    }
   }
 
   /**
@@ -350,7 +390,7 @@ public class QueryLexer {
     @Override
     public void _handleToken(String token, ScanContext ctx) throws InvalidQueryException {
       //don't add prop name token until after operator token
-      if (! SET_IGNORE.contains(token)) {
+      if (! ctx.getPropertiesToIgnore().contains(token)) {
         ctx.setPropertyOperand(token);
       } else {
         if (!ctx.getTokenList().isEmpty() ) {

+ 28 - 0
ambari-server/src/test/java/org/apache/ambari/server/api/predicate/QueryLexerTest.java

@@ -22,7 +22,11 @@ package org.apache.ambari.server.api.predicate;
 import org.junit.Test;
 
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
+
 import static org.junit.Assert.*;
 
 /**
@@ -303,6 +307,30 @@ public class QueryLexerTest {
     assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
   }
 
+  @Test
+  public void testTokens_ignore__userDefined() throws InvalidQueryException {
+    List<Token> listTokens = new ArrayList<Token>();
+    listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
+    listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
+    listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "1"));
+    listTokens.add(new Token(Token.TYPE.LOGICAL_OPERATOR, "&"));
+    listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR, "="));
+    listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "bar"));
+    listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "2"));
+
+    QueryLexer lexer = new QueryLexer();
+    Set<String> propertiesToIgnore = new HashSet<String>();
+    propertiesToIgnore.add("ignore1");
+    propertiesToIgnore.add("otherIgnore");
+    propertiesToIgnore.add("ba");
+    propertiesToIgnore.add("ple");
+
+    Token[] tokens = lexer.tokens("ba=gone&foo=1&ignore1=pleaseIgnoreMe&fields=a/b&bar=2&otherIgnore=byebye",
+        propertiesToIgnore);
+
+    assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]), tokens);
+  }
+
   @Test
   public void testTokens_invalidRelationalOp() {
     try {