Author: jspeidel
Date: Thu Jan 31 22:33:31 2013
New Revision: 1441233
URL: http://svn.apache.org/viewvc?rev=1441233&view=rev
Log:
AMBARI-1294. Add 'isEmpty' and 'in' query operators to API
Added:
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/InOperator.java
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/IsEmptyOperator.java
Modified:
incubator/ambari/trunk/CHANGES.txt
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/QueryLexer.java
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/QueryParser.java
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/Token.java
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/Expression.java
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/LogicalExpression.java
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/NotLogicalExpression.java
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/RelationalExpression.java
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/Operator.java
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/RelationalOperator.java
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/RelationalOperatorFactory.java
incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/TestSuite.java
incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/predicate/QueryLexerTest.java
incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/predicate/QueryParserTest.java
Modified: incubator/ambari/trunk/CHANGES.txt
URL:
http://svn.apache.org/viewvc/incubator/ambari/trunk/CHANGES.txt?rev=1441233&r1=1441232&r2=1441233&view=diff
==============================================================================
--- incubator/ambari/trunk/CHANGES.txt (original)
+++ incubator/ambari/trunk/CHANGES.txt Thu Jan 31 22:33:31 2013
@@ -12,6 +12,8 @@ Trunk (unreleased changes):
NEW FEATURES
+ AMBARI-1294. Add isEmpty() query operator support. (jspeidel)
+
AMBARI-1280. Support explicit predicate grouping in API queries. (jspeidel)
AMBARI-1180. Display host check status results given by the agent as part
Modified:
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/QueryLexer.java
URL:
http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/QueryLexer.java?rev=1441233&r1=1441232&r2=1441233&view=diff
==============================================================================
---
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/QueryLexer.java
(original)
+++
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/QueryLexer.java
Thu Jan 31 22:33:31 2013
@@ -30,13 +30,14 @@ import java.util.regex.Pattern;
* a regular expression which splits on a set of deliminators which includes
* operators and brackets.
*
- * Second, each string token is converted into a Token with type an value
information.
+ * Second, each string token is converted into a Token with type and value
information.
*/
public class QueryLexer {
/**
* All valid deliminators.
*/
- private static final String[] ALL_DELIMS =
{"<=",">=","!=","=","<",">","&","|","!","(", ")"};
+ private static final String[] ALL_DELIMS =
+ {".in\\(",".isEmpty\\(","<=",">=","!=","=","<",">","&","|","!","(", ")"};
/**
* Map of token type to list of valid handlers for next token.
@@ -54,6 +55,7 @@ public class QueryLexer {
* Register token handlers.
*/
public QueryLexer() {
+ //todo: refactor handler registration
List<TokenHandler> listHandlers = new ArrayList<TokenHandler>();
listHandlers.add(new LogicalUnaryOperatorTokenHandler());
listHandlers.add(new OpenBracketTokenHandler());
@@ -65,6 +67,7 @@ public class QueryLexer {
listHandlers= new ArrayList<TokenHandler>();
listHandlers.add(new RelationalOperatorTokenHandler());
+ listHandlers.add(new RelationalOperatorFuncTokenHandler());
TOKEN_HANDLERS.put(Token.TYPE.PROPERTY_OPERAND, listHandlers);
listHandlers = new ArrayList<TokenHandler>();
@@ -73,6 +76,11 @@ public class QueryLexer {
listHandlers = new ArrayList<TokenHandler>();
listHandlers.add(new CloseBracketTokenHandler());
+ listHandlers.add(new ValueOperandTokenHandler());
+ TOKEN_HANDLERS.put(Token.TYPE.RELATIONAL_OPERATOR_FUNC, listHandlers);
+
+ listHandlers = new ArrayList<TokenHandler>();
+ listHandlers.add(new CloseBracketTokenHandler());
listHandlers.add(new LogicalOperatorTokenHandler());
TOKEN_HANDLERS.put(Token.TYPE.VALUE_OPERAND, listHandlers);
TOKEN_HANDLERS.put(Token.TYPE.BRACKET_CLOSE, listHandlers);
@@ -90,7 +98,6 @@ public class QueryLexer {
public Token[] tokens(String exp) throws InvalidQueryException {
ScanContext ctx = new ScanContext();
-
for (String tok : parseStringTokens(exp)) {
List<TokenHandler> listHandlers =
TOKEN_HANDLERS.get(ctx.getLastTokenType());
boolean processed = false;
@@ -105,7 +112,6 @@ public class QueryLexer {
tok + "\', previous token type=" + ctx.getLastTokenType());
}
}
-
return ctx.getTokenList().toArray(new Token[ctx.getTokenList().size()]);
}
@@ -267,7 +273,6 @@ public class QueryLexer {
}
}
-
/**
* Token handler base class.
* Token handlers are responsible for processing specific token type.
@@ -365,7 +370,7 @@ public class QueryLexer {
@Override
public boolean handles(String token, Token.TYPE previousTokenType) {
- return token.matches("[^!&\\|<=|>=|!=|=|<|>\\(\\)]+");
+ return token.matches("[^!&\\|<=|>=|!=|=|<|>]+");
}
}
@@ -390,7 +395,7 @@ public class QueryLexer {
}
/**
- * Close Bracker token handler.
+ * Close Bracket token handler.
*/
private class CloseBracketTokenHandler extends TokenHandler {
@Override
@@ -414,7 +419,7 @@ public class QueryLexer {
*/
private class RelationalOperatorTokenHandler extends TokenHandler {
@Override
- public void _handleToken(String token, ScanContext ctx) throws
InvalidQueryException {
+ public void _handleToken(String token, ScanContext ctx) throws
InvalidQueryException {
ctx.addToken(new Token(Token.TYPE.RELATIONAL_OPERATOR, token));
ctx.addToken(new Token(Token.TYPE.PROPERTY_OPERAND,
ctx.getPropertyOperand()));
}
@@ -431,6 +436,29 @@ public class QueryLexer {
}
/**
+ * Relational Operator function token handler.
+ */
+ private class RelationalOperatorFuncTokenHandler extends TokenHandler {
+ @Override
+ public void _handleToken(String token, ScanContext ctx) throws
InvalidQueryException {
+ ctx.addToken(new Token(Token.TYPE.RELATIONAL_OPERATOR_FUNC, token));
+ ctx.addToken(new Token(Token.TYPE.PROPERTY_OPERAND,
ctx.getPropertyOperand()));
+ }
+
+ @Override
+ public Token.TYPE getType() {
+ return Token.TYPE.RELATIONAL_OPERATOR_FUNC;
+ }
+
+ //todo: add a unary relational operator func
+ @Override
+ public boolean handles(String token, Token.TYPE previousTokenType) {
+ return token.matches("\\.[a-zA-Z]+\\(");
+ }
+ }
+
+
+ /**
* Logical Operator token handler.
*/
private class LogicalOperatorTokenHandler extends TokenHandler {
Modified:
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/QueryParser.java
URL:
http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/QueryParser.java?rev=1441233&r1=1441232&r2=1441233&view=diff
==============================================================================
---
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/QueryParser.java
(original)
+++
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/QueryParser.java
Thu Jan 31 22:33:31 2013
@@ -51,6 +51,7 @@ public class QueryParser {
TOKEN_HANDLERS.put(Token.TYPE.LOGICAL_UNARY_OPERATOR, new
LogicalUnaryOperatorTokenHandler());
TOKEN_HANDLERS.put(Token.TYPE.PROPERTY_OPERAND, new
PropertyOperandTokenHandler());
TOKEN_HANDLERS.put(Token.TYPE.VALUE_OPERAND, new
ValueOperandTokenHandler());
+ TOKEN_HANDLERS.put(Token.TYPE.RELATIONAL_OPERATOR_FUNC, new
RelationalOperatorFuncTokenHandler());
}
/**
@@ -93,10 +94,10 @@ public class QueryParser {
* @throws InvalidQueryException if unable to properly parse the tokens into
a parse context
*/
private ParseContext parseExpressions(Token[] tokens) throws
InvalidQueryException {
- ParseContext ctx = new ParseContext();
+ ParseContext ctx = new ParseContext(tokens);
- for (Token token : tokens) {
- TOKEN_HANDLERS.get(token.getType()).handleToken(token, ctx);
+ while (ctx.getCurrentTokensIndex() < tokens.length) {
+
TOKEN_HANDLERS.get(tokens[ctx.getCurrentTokensIndex()].getType()).handleToken(ctx);
}
if (ctx.getPrecedenceLevel() != 0) {
@@ -128,10 +129,8 @@ public class QueryParser {
stack.addAll(exp.merge(left, right, precedenceLevel));
}
return mergeExpressions(new ArrayList<Expression>(stack),
precedenceLevel - 1);
-
- } else {
- return listExpressions;
}
+ return listExpressions;
}
/**
@@ -144,6 +143,16 @@ public class QueryParser {
private int m_precedence = 0;
/**
+ * Current position in tokens array
+ */
+ private int m_tokensIdx = 0;
+
+ /**
+ * Tokens
+ */
+ private Token[] m_tokens;
+
+ /**
* The type of the previous token used in validation.
*/
private Token.TYPE m_previousTokenType = null;
@@ -158,6 +167,35 @@ public class QueryParser {
*/
int m_maxPrecedence = 0;
+ public ParseContext(Token[] tokens) {
+ m_tokens = tokens;
+ }
+
+ /**
+ * Get array of all tokens.
+ * @return token array
+ */
+ public Token[] getTokens() {
+ return m_tokens;
+ }
+
+ /**
+ * Get the current position in the tokens array.
+ * @return the current tokens index
+ */
+ public int getCurrentTokensIndex() {
+ return m_tokensIdx;
+ }
+
+ /**
+ * Set the current position in the tokens array.
+ * Each handler should set this value after processing a token(s).
+ * @param idx current tokens index
+ */
+ public void setCurrentTokensIndex(int idx) {
+ m_tokensIdx = idx;
+ }
+
/**
* Increment the context precedence level.
*
@@ -267,28 +305,29 @@ public class QueryParser {
* Process a token. Handles common token processing functionality then
delegates to the individual
* concrete handlers.
*
- * @param token the token to process
* @param ctx the current parse context
* @throws InvalidQueryException if unable to process the token
*/
- public void handleToken(Token token, ParseContext ctx) throws
InvalidQueryException {
+ public void handleToken(ParseContext ctx) throws InvalidQueryException {
+ Token token = ctx.getTokens()[ctx.getCurrentTokensIndex()];
if (! validate(ctx.getPreviousTokenType())) {
throw new InvalidQueryException("Unexpected token encountered in query
string. Last Token Type=" +
ctx.getPreviousTokenType() + ", Current Token[type=" +
token.getType() +
", value='" + token.getValue() + "']");
}
ctx.setTokenType(token.getType());
- _handleToken(token, ctx);
+
+ int idxIncrement = _handleToken(ctx);
+ ctx.setCurrentTokensIndex(ctx.getCurrentTokensIndex() + idxIncrement);
}
/**
* Process a token.
*
- * @param token the token to process
* @param ctx the current parse context
* @throws InvalidQueryException if unable to process the token
*/
- public abstract void _handleToken(Token token, ParseContext ctx) throws
InvalidQueryException;
+ public abstract int _handleToken(ParseContext ctx) throws
InvalidQueryException;
/**
* Validate the token based on the previous token.
@@ -305,8 +344,9 @@ public class QueryParser {
private class BracketOpenTokenHandler extends TokenHandler {
@Override
- public void _handleToken(Token token, ParseContext ctx) {
+ public int _handleToken(ParseContext ctx) {
ctx.incPrecedenceLevel(Operator.MAX_OP_PRECEDENCE);
+ return 1;
}
@Override
@@ -323,8 +363,10 @@ public class QueryParser {
*/
private class BracketCloseTokenHandler extends TokenHandler {
@Override
- public void _handleToken(Token token, ParseContext ctx) throws
InvalidQueryException{
+ public int _handleToken(ParseContext ctx) throws InvalidQueryException{
ctx.decPrecedenceLevel(Operator.MAX_OP_PRECEDENCE);
+
+ return 1;
}
@Override
@@ -339,10 +381,55 @@ public class QueryParser {
*/
private class RelationalOperatorTokenHandler extends TokenHandler {
@Override
- public void _handleToken(Token token, ParseContext ctx) throws
InvalidQueryException {
+ public int _handleToken(ParseContext ctx) throws InvalidQueryException {
+ Token token = ctx.getTokens()[ctx.getCurrentTokensIndex()];
RelationalOperator relationalOp =
RelationalOperatorFactory.createOperator(token.getValue());
//todo: use factory to create expression
ctx.addExpression(new RelationalExpression(relationalOp));
+
+ return 1;
+ }
+
+ @Override
+ public boolean validate(Token.TYPE previousTokenType) {
+ return previousTokenType == null ||
+ previousTokenType == Token.TYPE.BRACKET_OPEN ||
+ previousTokenType == Token.TYPE.LOGICAL_OPERATOR ||
+ previousTokenType == Token.TYPE.LOGICAL_UNARY_OPERATOR;
+ }
+ }
+
+ /**
+ * Relational Operator function token handler
+ */
+ private class RelationalOperatorFuncTokenHandler extends TokenHandler {
+ @Override
+ public int _handleToken(ParseContext ctx) throws InvalidQueryException {
+ Token[] tokens = ctx.getTokens();
+ int idx = ctx.getCurrentTokensIndex();
+ Token token = tokens[idx];
+ RelationalOperator relationalOp =
RelationalOperatorFactory.createOperator(token.getValue());
+
+ ctx.addExpression(new RelationalExpression(relationalOp));
+ ctx.setCurrentTokensIndex(++idx);
+
+ TokenHandler propertyHandler = new PropertyOperandTokenHandler();
+ propertyHandler.handleToken(ctx);
+
+ // handle right operand if applicable to operator
+ idx = ctx.getCurrentTokensIndex();
+ if (ctx.getCurrentTokensIndex() < tokens.length &&
+ tokens[idx].getType().equals(Token.TYPE.VALUE_OPERAND)) {
+ TokenHandler valueHandler = new ValueOperandTokenHandler();
+ valueHandler.handleToken(ctx);
+ }
+
+ // skip closing bracket
+ idx = ctx.getCurrentTokensIndex();
+ if (idx >= tokens.length || tokens[idx].getType() !=
Token.TYPE.BRACKET_CLOSE) {
+ throw new InvalidQueryException("Missing closing bracket for in
expression.") ;
+ }
+ return 1;
}
@Override
@@ -359,10 +446,13 @@ public class QueryParser {
*/
private class LogicalOperatorTokenHandler extends TokenHandler {
@Override
- public void _handleToken(Token token, ParseContext ctx) throws
InvalidQueryException {
+ public int _handleToken(ParseContext ctx) throws InvalidQueryException {
+ Token token = ctx.getTokens()[ctx.getCurrentTokensIndex()];
LogicalOperator logicalOp =
LogicalOperatorFactory.createOperator(token.getValue(),
ctx.getPrecedenceLevel());
ctx.updateMaxPrecedence(logicalOp.getPrecedence());
ctx.addExpression(LogicalExpressionFactory.createLogicalExpression(logicalOp));
+
+ return 1;
}
@Override
@@ -389,13 +479,17 @@ public class QueryParser {
*/
private class PropertyOperandTokenHandler extends TokenHandler {
@Override
- public void _handleToken(Token token, ParseContext ctx) throws
InvalidQueryException {
+ public int _handleToken(ParseContext ctx) throws InvalidQueryException {
+ Token token = ctx.getTokens()[ctx.getCurrentTokensIndex()];
ctx.getPrecedingExpression().setLeftOperand(token.getValue());
+
+ return 1;
}
@Override
public boolean validate(Token.TYPE previousTokenType) {
- return previousTokenType == Token.TYPE.RELATIONAL_OPERATOR;
+ return previousTokenType == Token.TYPE.RELATIONAL_OPERATOR ||
+ previousTokenType == Token.TYPE.RELATIONAL_OPERATOR_FUNC;
}
}
@@ -404,8 +498,11 @@ public class QueryParser {
*/
private class ValueOperandTokenHandler extends TokenHandler {
@Override
- public void _handleToken(Token token, ParseContext ctx) throws
InvalidQueryException {
+ public int _handleToken(ParseContext ctx) throws InvalidQueryException {
+ Token token = ctx.getTokens()[ctx.getCurrentTokensIndex()];
ctx.getPrecedingExpression().setRightOperand(token.getValue());
+
+ return 1;
}
@Override
Modified:
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/Token.java
URL:
http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/Token.java?rev=1441233&r1=1441232&r2=1441233&view=diff
==============================================================================
---
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/Token.java
(original)
+++
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/Token.java
Thu Jan 31 22:33:31 2013
@@ -34,6 +34,8 @@ public class Token {
VALUE_OPERAND,
/** Relational operator */
RELATIONAL_OPERATOR,
+ /** Relational operator function */
+ RELATIONAL_OPERATOR_FUNC,
/** Logical operator */
LOGICAL_OPERATOR,
/** Logical unary operator such as !*/
Modified:
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/Expression.java
URL:
http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/Expression.java?rev=1441233&r1=1441232&r2=1441233&view=diff
==============================================================================
---
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/Expression.java
(original)
+++
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/Expression.java
Thu Jan 31 22:33:31 2013
@@ -18,6 +18,7 @@
package org.apache.ambari.server.api.predicate.expressions;
+import org.apache.ambari.server.api.predicate.InvalidQueryException;
import org.apache.ambari.server.api.predicate.operators.Operator;
import org.apache.ambari.server.controller.spi.Predicate;
@@ -49,7 +50,7 @@ public interface Expression<T> {
* Get the predicate representation of the expression.
* @return a predicate instance for the expression
*/
- public Predicate toPredicate();
+ public Predicate toPredicate() throws InvalidQueryException;
/**
* Set the expressions left operand.
Modified:
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/LogicalExpression.java
URL:
http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/LogicalExpression.java?rev=1441233&r1=1441232&r2=1441233&view=diff
==============================================================================
---
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/LogicalExpression.java
(original)
+++
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/LogicalExpression.java
Thu Jan 31 22:33:31 2013
@@ -18,6 +18,7 @@
package org.apache.ambari.server.api.predicate.expressions;
+import org.apache.ambari.server.api.predicate.InvalidQueryException;
import org.apache.ambari.server.api.predicate.operators.LogicalOperator;
import org.apache.ambari.server.controller.spi.Predicate;
@@ -42,7 +43,7 @@ public class LogicalExpression extends A
@Override
- public Predicate toPredicate() {
+ public Predicate toPredicate() throws InvalidQueryException {
return ((LogicalOperator) getOperator()).
toPredicate(getLeftOperand().toPredicate(),
getRightOperand().toPredicate());
}
Modified:
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/NotLogicalExpression.java
URL:
http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/NotLogicalExpression.java?rev=1441233&r1=1441232&r2=1441233&view=diff
==============================================================================
---
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/NotLogicalExpression.java
(original)
+++
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/NotLogicalExpression.java
Thu Jan 31 22:33:31 2013
@@ -18,6 +18,7 @@
package org.apache.ambari.server.api.predicate.expressions;
+import org.apache.ambari.server.api.predicate.InvalidQueryException;
import org.apache.ambari.server.api.predicate.operators.LogicalOperator;
import org.apache.ambari.server.controller.predicate.BasePredicate;
import org.apache.ambari.server.controller.predicate.NotPredicate;
@@ -57,7 +58,7 @@ public class NotLogicalExpression extend
}
@Override
- public Predicate toPredicate() {
+ public Predicate toPredicate() throws InvalidQueryException {
//todo: remove need to down cast to BasePredicate
return new NotPredicate((BasePredicate) getRightOperand().toPredicate());
}
Modified:
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/RelationalExpression.java
URL:
http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/RelationalExpression.java?rev=1441233&r1=1441232&r2=1441233&view=diff
==============================================================================
---
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/RelationalExpression.java
(original)
+++
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/expressions/RelationalExpression.java
Thu Jan 31 22:33:31 2013
@@ -18,6 +18,7 @@
package org.apache.ambari.server.api.predicate.expressions;
+import org.apache.ambari.server.api.predicate.InvalidQueryException;
import org.apache.ambari.server.api.predicate.operators.RelationalOperator;
import org.apache.ambari.server.controller.spi.Predicate;
@@ -38,7 +39,7 @@ public class RelationalExpression extend
}
@Override
- public Predicate toPredicate() {
+ public Predicate toPredicate() throws InvalidQueryException {
return ((RelationalOperator) getOperator()).
toPredicate(getLeftOperand(), getRightOperand());
}
Added:
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/InOperator.java
URL:
http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/InOperator.java?rev=1441233&view=auto
==============================================================================
---
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/InOperator.java
(added)
+++
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/InOperator.java
Thu Jan 31 22:33:31 2013
@@ -0,0 +1,54 @@
+package org.apache.ambari.server.api.predicate.operators;
+
+import org.apache.ambari.server.api.predicate.InvalidQueryException;
+import org.apache.ambari.server.controller.predicate.BasePredicate;
+import org.apache.ambari.server.controller.predicate.EqualsPredicate;
+import org.apache.ambari.server.controller.predicate.OrPredicate;
+import org.apache.ambari.server.controller.spi.Predicate;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * IN relational operator.
+ * This is a binary operator which takes a comma delimited right operand and
+ * creates equals predicates with the left operand and each right operand
token.
+ * The equals predicates are combined with an OR predicate.
+ *
+ */
+public class InOperator extends AbstractOperator implements RelationalOperator
{
+
+ public InOperator() {
+ super(0);
+ }
+
+ @Override
+ public String getName() {
+ return "InOperator";
+ }
+
+ @Override
+ public Predicate toPredicate(String prop, String val) throws
InvalidQueryException {
+
+ if (val == null) {
+ throw new InvalidQueryException("IN operator is missing a required right
operand.");
+ }
+
+ String[] tokens = val.split(",");
+ List<EqualsPredicate> listPredicates = new ArrayList<EqualsPredicate>();
+ for (String token : tokens) {
+ listPredicates.add(new EqualsPredicate(prop, token.trim()));
+ }
+ return listPredicates.size() == 1 ? listPredicates.get(0) :
+ buildOrPredicate(listPredicates);
+ }
+
+ private OrPredicate buildOrPredicate(List<EqualsPredicate> listPredicates) {
+ return new OrPredicate(listPredicates.toArray(new
BasePredicate[listPredicates.size()]));
+ }
+
+ @Override
+ public TYPE getType() {
+ return TYPE.IN;
+ }
+}
Added:
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/IsEmptyOperator.java
URL:
http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/IsEmptyOperator.java?rev=1441233&view=auto
==============================================================================
---
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/IsEmptyOperator.java
(added)
+++
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/IsEmptyOperator.java
Thu Jan 31 22:33:31 2013
@@ -0,0 +1,51 @@
+/**
+ * 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 org.apache.ambari.server.api.predicate.operators;
+
+import org.apache.ambari.server.api.predicate.InvalidQueryException;
+import org.apache.ambari.server.controller.predicate.CategoryIsEmptyPredicate;
+import org.apache.ambari.server.controller.spi.Predicate;
+
+/**
+ * Operator that is used to determine if a category is empty, meaning that it
doesn't
+ * contain any properties.
+ */
+public class IsEmptyOperator extends AbstractOperator implements
RelationalOperator {
+ public IsEmptyOperator() {
+ super(0);
+ }
+
+ @Override
+ public String getName() {
+ return "IsEmptyOperator";
+ }
+
+ @Override
+ public Predicate toPredicate(String prop, String val) throws
InvalidQueryException {
+ if (val != null) {
+ throw new InvalidQueryException("'isEmpty' operator shouldn't have a
right operand but one exists: " + val);
+ }
+ return new CategoryIsEmptyPredicate(prop);
+ }
+
+ @Override
+ public TYPE getType() {
+ return TYPE.IS_EMPTY;
+ }
+}
Modified:
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/Operator.java
URL:
http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/Operator.java?rev=1441233&r1=1441232&r2=1441233&view=diff
==============================================================================
---
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/Operator.java
(original)
+++
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/Operator.java
Thu Jan 31 22:33:31 2013
@@ -35,7 +35,9 @@ public interface Operator {
NOT_EQUAL,
AND,
OR,
- NOT
+ NOT,
+ IN,
+ IS_EMPTY
}
/**
Modified:
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/RelationalOperator.java
URL:
http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/RelationalOperator.java?rev=1441233&r1=1441232&r2=1441233&view=diff
==============================================================================
---
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/RelationalOperator.java
(original)
+++
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/RelationalOperator.java
Thu Jan 31 22:33:31 2013
@@ -18,6 +18,7 @@
package org.apache.ambari.server.api.predicate.operators;
+import org.apache.ambari.server.api.predicate.InvalidQueryException;
import org.apache.ambari.server.controller.spi.Predicate;
/**
@@ -30,6 +31,7 @@ public interface RelationalOperator exte
* @param prop left operand
* @param val right operand
* @return a predicate instance for this operator.
+ * @throws InvalidQueryException if unable to build the predicate because
of invalid operands
*/
- public Predicate toPredicate(String prop, String val);
+ public Predicate toPredicate(String prop, String val) throws
InvalidQueryException;
}
Modified:
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/RelationalOperatorFactory.java
URL:
http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/RelationalOperatorFactory.java?rev=1441233&r1=1441232&r2=1441233&view=diff
==============================================================================
---
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/RelationalOperatorFactory.java
(original)
+++
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/api/predicate/operators/RelationalOperatorFactory.java
Thu Jan 31 22:33:31 2013
@@ -29,7 +29,8 @@ public class RelationalOperatorFactory {
* of the operator.
*
* @param operator the string representation of the operator
- * @return relationl operator for the given string
+ *
+ * @return relational operator for the given string
* @throws InvalidQueryException if an invalid operator is passed in
*/
public static RelationalOperator createOperator(String operator) throws
InvalidQueryException {
@@ -37,14 +38,18 @@ public class RelationalOperatorFactory {
return new NotEqualsOperator();
} else if ("=".equals(operator)) {
return new EqualsOperator();
- } if ("<=".equals(operator)) {
+ } else if ("<=".equals(operator)) {
return new LessEqualsOperator();
- } if ("<".equals(operator)) {
+ } else if ("<".equals(operator)) {
return new LessOperator();
- }else if (">=".equals(operator)) {
+ } else if (">=".equals(operator)) {
return new GreaterEqualsOperator();
- } if (">".equals(operator)) {
+ } else if (">".equals(operator)) {
return new GreaterOperator();
+ } else if (".in(".equals(operator)) {
+ return new InOperator();
+ } else if (".isEmpty(".equals(operator)) {
+ return new IsEmptyOperator();
} else {
throw new RuntimeException("Invalid Operator Type: " + operator);
}
Modified:
incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/TestSuite.java
URL:
http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/TestSuite.java?rev=1441233&r1=1441232&r2=1441233&view=diff
==============================================================================
---
incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/TestSuite.java
(original)
+++
incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/TestSuite.java
Thu Jan 31 22:33:31 2013
@@ -25,6 +25,7 @@ package org.apache.ambari.server.api;
import org.apache.ambari.server.api.handlers.*;
import org.apache.ambari.server.api.predicate.QueryLexerTest;
import org.apache.ambari.server.api.predicate.QueryParserTest;
+import org.apache.ambari.server.api.predicate.operators.*;
import org.apache.ambari.server.api.query.QueryImplTest;
import org.apache.ambari.server.api.resources.ResourceInstanceImplTest;
import org.apache.ambari.server.api.services.*;
@@ -39,6 +40,9 @@ import org.junit.runners.Suite;
JsonPropertyParserTest.class, CreateHandlerTest.class,
UpdateHandlerTest.class, DeleteHandlerTest.class,
PersistenceManagerImplTest.class, GetRequestTest.class,
PutRequestTest.class, PostRequestTest.class,
DeleteRequestTest.class, JsonSerializerTest.class,
QueryCreateHandlerTest.class, ResourceInstanceImplTest.class,
- QueryLexerTest.class, QueryParserTest.class})
+ QueryLexerTest.class, QueryParserTest.class, IsEmptyOperatorTest.class,
InOperatorTest.class,
+ AndOperatorTest.class, OrOperatorTest.class, EqualsOperatorTest.class,
GreaterEqualsOperatorTest.class,
+ GreaterOperatorTest.class, LessEqualsOperatorTest.class,
LessEqualsOperatorTest.class, NotEqualsOperatorTest.class,
+ NotOperatorTest.class})
public class TestSuite {
}
Modified:
incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/predicate/QueryLexerTest.java
URL:
http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/predicate/QueryLexerTest.java?rev=1441233&r1=1441232&r2=1441233&view=diff
==============================================================================
---
incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/predicate/QueryLexerTest.java
(original)
+++
incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/predicate/QueryLexerTest.java
Thu Jan 31 22:33:31 2013
@@ -84,14 +84,40 @@ public class QueryLexerTest {
@Test
public void testUnaryNot() throws Exception {
+ QueryLexer lexer = new QueryLexer();
+ Token[] tokens = lexer.tokens("!foo<5");
+
List<Token> listTokens = new ArrayList<Token>();
listTokens.add(new Token(Token.TYPE.LOGICAL_UNARY_OPERATOR, "!"));
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, "5"));
+ assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]),
tokens);
+ }
+ @Test
+ public void testInOperator() throws Exception {
QueryLexer lexer = new QueryLexer();
- Token[] tokens = lexer.tokens("!foo<5");
+ Token[] tokens = lexer.tokens("foo.in(one, two, 3)");
+
+ List<Token> listTokens = new ArrayList<Token>();
+ listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR_FUNC, ".in("));
+ listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
+ listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "one, two, 3"));
+ listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
+
+ assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]),
tokens);
+ }
+
+ @Test
+ public void testIsEmptyOperator() throws Exception {
+ QueryLexer lexer = new QueryLexer();
+ Token[] tokens = lexer.tokens("category1.isEmpty()");
+
+ List<Token> listTokens = new ArrayList<Token>();
+ listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR_FUNC,
".isEmpty("));
+ listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "category1"));
+ listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
assertArrayEquals(listTokens.toArray(new Token[listTokens.size()]),
tokens);
}
Modified:
incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/predicate/QueryParserTest.java
URL:
http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/predicate/QueryParserTest.java?rev=1441233&r1=1441232&r2=1441233&view=diff
==============================================================================
---
incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/predicate/QueryParserTest.java
(original)
+++
incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/api/predicate/QueryParserTest.java
Thu Jan 31 22:33:31 2013
@@ -114,7 +114,7 @@ public class QueryParserTest {
}
@Test
- public void testParse_simpleNotOp() throws Exception {
+ public void testParse_NotOp__simple() throws Exception {
List<Token> listTokens = new ArrayList<Token>();
//!a=b
listTokens.add(new Token(Token.TYPE.LOGICAL_UNARY_OPERATOR, "!"));
@@ -153,6 +153,93 @@ public class QueryParserTest {
}
@Test
+ public void testParse_InOp__simple() throws Exception {
+ List<Token> listTokens = new ArrayList<Token>();
+ // foo.in(one,two,3)
+ listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR_FUNC, ".in("));
+ listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
+ listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "one,two,3"));
+ listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
+
+ QueryParser parser = new QueryParser();
+ Predicate p = parser.parse(listTokens.toArray(new
Token[listTokens.size()]));
+
+ EqualsPredicate ep1 = new EqualsPredicate("foo", "one");
+ EqualsPredicate ep2 = new EqualsPredicate("foo", "two");
+ EqualsPredicate ep3 = new EqualsPredicate("foo", "3");
+
+ OrPredicate orPredicate = new OrPredicate(ep1, ep2, ep3);
+
+ assertEquals(orPredicate, p);
+ }
+
+ @Test
+ public void testParse_InOp__exception() throws Exception {
+ List<Token> listTokens = new ArrayList<Token>();
+ // foo.in()
+ listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR_FUNC, ".in("));
+ listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "foo"));
+ listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
+
+ QueryParser parser = new QueryParser();
+ try {
+ parser.parse(listTokens.toArray(new Token[listTokens.size()]));
+ fail("Expected InvalidQueryException due to missing right operand");
+ } catch (InvalidQueryException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testParse_isEmptyOp__simple() throws Exception {
+ List<Token> listTokens = new ArrayList<Token>();
+ // category1.isEmpty()
+ listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR_FUNC,
".isEmpty("));
+ listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "category1"));
+ listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
+
+ QueryParser parser = new QueryParser();
+ Predicate p = parser.parse(listTokens.toArray(new
Token[listTokens.size()]));
+
+ assertEquals(new CategoryIsEmptyPredicate("category1"), p);
+ }
+
+ @Test
+ public void testParse_isEmptyOp__exception() throws Exception {
+ List<Token> listTokens = new ArrayList<Token>();
+ // category1.isEmpty()
+ listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR_FUNC,
".isEmpty("));
+ listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "category1"));
+ // missing closing bracket
+
+ QueryParser parser = new QueryParser();
+ try {
+ parser.parse(listTokens.toArray(new Token[listTokens.size()]));
+ fail("Expected InvalidQueryException due to missing closing bracket");
+ } catch (InvalidQueryException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testParse_isEmptyOp__exception2() throws Exception {
+ List<Token> listTokens = new ArrayList<Token>();
+ // category1.isEmpty()
+ listTokens.add(new Token(Token.TYPE.RELATIONAL_OPERATOR_FUNC,
".isEmpty("));
+ listTokens.add(new Token(Token.TYPE.PROPERTY_OPERAND, "category1"));
+ listTokens.add(new Token(Token.TYPE.VALUE_OPERAND, "one,two,3"));
+ listTokens.add(new Token(Token.TYPE.BRACKET_CLOSE, ")"));
+
+ QueryParser parser = new QueryParser();
+ try {
+ parser.parse(listTokens.toArray(new Token[listTokens.size()]));
+ fail("Expected InvalidQueryException due to existence of right operand");
+ } catch (InvalidQueryException e) {
+ // expected
+ }
+ }
+
+ @Test
public void testParse_noTokens() throws InvalidQueryException {
assertNull(new QueryParser().parse(new Token[0]));
}