http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/Expression.java ---------------------------------------------------------------------- diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/Expression.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/Expression.java new file mode 100644 index 0000000..3e6d9b3 --- /dev/null +++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/Expression.java @@ -0,0 +1,38 @@ +/* + * 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.rocketmq.filter.expression; + +/** + * Interface of expression. + * <p> + * This class was taken from ActiveMQ org.apache.activemq.filter.Expression, + * but the parameter is changed to an interface. + * </p> + * + * @see org.apache.rocketmq.filter.expression.EvaluationContext + */ +public interface Expression { + + /** + * Calculate express result with context. + * + * @param context context of evaluation + * @return the value of this expression + */ + Object evaluate(EvaluationContext context) throws Exception; +}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/LogicExpression.java ---------------------------------------------------------------------- diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/LogicExpression.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/LogicExpression.java new file mode 100644 index 0000000..1062bb8 --- /dev/null +++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/LogicExpression.java @@ -0,0 +1,94 @@ +/* + * 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.rocketmq.filter.expression; + +/** + * A filter performing a comparison of two objects + * <p> + * This class was taken from ActiveMQ org.apache.activemq.filter.LogicExpression, + * </p> + */ +public abstract class LogicExpression extends BinaryExpression implements BooleanExpression { + + /** + * @param left + * @param right + */ + public LogicExpression(BooleanExpression left, BooleanExpression right) { + super(left, right); + } + + public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue) { + return new LogicExpression(lvalue, rvalue) { + + public Object evaluate(EvaluationContext context) throws Exception { + + Boolean lv = (Boolean) left.evaluate(context); + if (lv != null && lv.booleanValue()) { + return Boolean.TRUE; + } + Boolean rv = (Boolean) right.evaluate(context); + if (rv != null && rv.booleanValue()) { + return Boolean.TRUE; + } + if (lv == null || rv == null) { + return null; + } + return Boolean.FALSE; + } + + public String getExpressionSymbol() { + return "||"; + } + }; + } + + public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue) { + return new LogicExpression(lvalue, rvalue) { + + public Object evaluate(EvaluationContext context) throws Exception { + + Boolean lv = (Boolean) left.evaluate(context); + + if (lv != null && !lv.booleanValue()) { + return Boolean.FALSE; + } + Boolean rv = (Boolean) right.evaluate(context); + if (rv != null && !rv.booleanValue()) { + return Boolean.FALSE; + } + if (lv == null || rv == null) { + return null; + } + return Boolean.TRUE; + } + + public String getExpressionSymbol() { + return "&&"; + } + }; + } + + public abstract Object evaluate(EvaluationContext context) throws Exception; + + public boolean matches(EvaluationContext context) throws Exception { + Object object = evaluate(context); + return object != null && object == Boolean.TRUE; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/MQFilterException.java ---------------------------------------------------------------------- diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/MQFilterException.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/MQFilterException.java new file mode 100644 index 0000000..676a17b --- /dev/null +++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/MQFilterException.java @@ -0,0 +1,46 @@ +/* + * 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.rocketmq.filter.expression; + +/** + * Exception. + */ +public class MQFilterException extends Exception { + private static final long serialVersionUID = 1L; + private final int responseCode; + private final String errorMessage; + + public MQFilterException(String errorMessage, Throwable cause) { + super(cause); + this.responseCode = -1; + this.errorMessage = errorMessage; + } + + public MQFilterException(int responseCode, String errorMessage) { + this.responseCode = responseCode; + this.errorMessage = errorMessage; + } + + public int getResponseCode() { + return responseCode; + } + + public String getErrorMessage() { + return errorMessage; + } +} http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/NowExpression.java ---------------------------------------------------------------------- diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/NowExpression.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/NowExpression.java new file mode 100644 index 0000000..d76caca --- /dev/null +++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/NowExpression.java @@ -0,0 +1,36 @@ +/* + * 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.rocketmq.filter.expression; + +/** + * Current time expression.Just for test. + */ +public class NowExpression extends ConstantExpression { + public NowExpression() { + super("now"); + } + + @Override + public Object evaluate(EvaluationContext context) throws Exception { + return new Long(System.currentTimeMillis()); + } + + public Object getValue() { + return new Long(System.currentTimeMillis()); + } +} http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/PropertyExpression.java ---------------------------------------------------------------------- diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/PropertyExpression.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/PropertyExpression.java new file mode 100644 index 0000000..b9657b0 --- /dev/null +++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/PropertyExpression.java @@ -0,0 +1,70 @@ +/* + * 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.rocketmq.filter.expression; + +/** + * Represents a property expression + * <p> + * This class was taken from ActiveMQ org.apache.activemq.filter.PropertyExpression, + * but more simple and no transfer between expression and message property. + * </p> + */ +public class PropertyExpression implements Expression { + private final String name; + + public PropertyExpression(String name) { + this.name = name; + } + + @Override + public Object evaluate(EvaluationContext context) throws Exception { + return context.get(name); + } + + public String getName() { + return name; + } + + /** + * @see Object#toString() + */ + @Override + public String toString() { + return name; + } + + /** + * @see Object#hashCode() + */ + @Override + public int hashCode() { + return name.hashCode(); + } + + /** + * @see Object#equals(Object) + */ + @Override + public boolean equals(Object o) { + + if (o == null || !this.getClass().equals(o.getClass())) { + return false; + } + return name.equals(((PropertyExpression) o).name); + } +} http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryExpression.java ---------------------------------------------------------------------- diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryExpression.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryExpression.java new file mode 100644 index 0000000..0519f4d --- /dev/null +++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryExpression.java @@ -0,0 +1,267 @@ +/* + * 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.rocketmq.filter.expression; + +import org.apache.rocketmq.filter.constant.UnaryType; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +/** + * An expression which performs an operation on two expression values + * <p> + * This class was taken from ActiveMQ org.apache.activemq.filter.UnaryExpression, + * but: + * 1. remove XPath and XQuery expression; + * 2. Add constant UnaryType to distinguish different unary expression; + * 3. Extract UnaryInExpression to an independent class. + * </p> + */ +public abstract class UnaryExpression implements Expression { + + private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE); + protected Expression right; + + public UnaryType unaryType; + + public UnaryExpression(Expression left) { + this.right = left; + } + + public UnaryExpression(Expression left, UnaryType unaryType) { + this.setUnaryType(unaryType); + this.right = left; + } + + public static Expression createNegate(Expression left) { + return new UnaryExpression(left, UnaryType.NEGATE) { + public Object evaluate(EvaluationContext context) throws Exception { + Object rvalue = right.evaluate(context); + if (rvalue == null) { + return null; + } + if (rvalue instanceof Number) { + return negate((Number) rvalue); + } + return null; + } + + public String getExpressionSymbol() { + return "-"; + } + }; + } + + public static BooleanExpression createInExpression(PropertyExpression right, List<Object> elements, + final boolean not) { + + // Use a HashSet if there are many elements. + Collection<Object> t; + if (elements.size() == 0) { + t = null; + } else if (elements.size() < 5) { + t = elements; + } else { + t = new HashSet<Object>(elements); + } + final Collection inList = t; + + return new UnaryInExpression(right, UnaryType.IN, inList, not) { + public Object evaluate(EvaluationContext context) throws Exception { + + Object rvalue = right.evaluate(context); + if (rvalue == null) { + return null; + } + if (rvalue.getClass() != String.class) { + return null; + } + + if ((inList != null && inList.contains(rvalue)) ^ not) { + return Boolean.TRUE; + } else { + return Boolean.FALSE; + } + + } + + public String toString() { + StringBuffer answer = new StringBuffer(); + answer.append(right); + answer.append(" "); + answer.append(getExpressionSymbol()); + answer.append(" ( "); + + int count = 0; + for (Iterator i = inList.iterator(); i.hasNext(); ) { + Object o = (Object) i.next(); + if (count != 0) { + answer.append(", "); + } + answer.append(o); + count++; + } + + answer.append(" )"); + return answer.toString(); + } + + public String getExpressionSymbol() { + if (not) { + return "NOT IN"; + } else { + return "IN"; + } + } + }; + } + + abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression { + public BooleanUnaryExpression(Expression left, UnaryType unaryType) { + super(left, unaryType); + } + + public boolean matches(EvaluationContext context) throws Exception { + Object object = evaluate(context); + return object != null && object == Boolean.TRUE; + } + } + + public static BooleanExpression createNOT(BooleanExpression left) { + return new BooleanUnaryExpression(left, UnaryType.NOT) { + public Object evaluate(EvaluationContext context) throws Exception { + Boolean lvalue = (Boolean) right.evaluate(context); + if (lvalue == null) { + return null; + } + return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE; + } + + public String getExpressionSymbol() { + return "NOT"; + } + }; + } + + public static BooleanExpression createBooleanCast(Expression left) { + return new BooleanUnaryExpression(left, UnaryType.BOOLEANCAST) { + public Object evaluate(EvaluationContext context) throws Exception { + Object rvalue = right.evaluate(context); + if (rvalue == null) { + return null; + } + if (!rvalue.getClass().equals(Boolean.class)) { + return Boolean.FALSE; + } + return ((Boolean) rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE; + } + + public String toString() { + return right.toString(); + } + + public String getExpressionSymbol() { + return ""; + } + }; + } + + private static Number negate(Number left) { + Class clazz = left.getClass(); + if (clazz == Integer.class) { + return new Integer(-left.intValue()); + } else if (clazz == Long.class) { + return new Long(-left.longValue()); + } else if (clazz == Float.class) { + return new Float(-left.floatValue()); + } else if (clazz == Double.class) { + return new Double(-left.doubleValue()); + } else if (clazz == BigDecimal.class) { + // We ussually get a big deciamal when we have Long.MIN_VALUE + // constant in the + // Selector. Long.MIN_VALUE is too big to store in a Long as a + // positive so we store it + // as a Big decimal. But it gets Negated right away.. to here we try + // to covert it back + // to a Long. + BigDecimal bd = (BigDecimal) left; + bd = bd.negate(); + + if (BD_LONG_MIN_VALUE.compareTo(bd) == 0) { + return Long.valueOf(Long.MIN_VALUE); + } + return bd; + } else { + throw new RuntimeException("Don't know how to negate: " + left); + } + } + + public Expression getRight() { + return right; + } + + public void setRight(Expression expression) { + right = expression; + } + + public UnaryType getUnaryType() { + return unaryType; + } + + public void setUnaryType(UnaryType unaryType) { + this.unaryType = unaryType; + } + + /** + * @see Object#toString() + */ + public String toString() { + return "(" + getExpressionSymbol() + " " + right.toString() + ")"; + } + + /** + * @see Object#hashCode() + */ + public int hashCode() { + return toString().hashCode(); + } + + /** + * @see Object#equals(Object) + */ + public boolean equals(Object o) { + + if (o == null || !this.getClass().equals(o.getClass())) { + return false; + } + return toString().equals(o.toString()); + + } + + /** + * Returns the symbol that represents this binary expression. For example, + * addition is represented by "+" + * + * @return + */ + public abstract String getExpressionSymbol(); + +} http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryInExpression.java ---------------------------------------------------------------------- diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryInExpression.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryInExpression.java new file mode 100644 index 0000000..7d9083c --- /dev/null +++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryInExpression.java @@ -0,0 +1,61 @@ +/* + * 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.rocketmq.filter.expression; + +import org.apache.rocketmq.filter.constant.UnaryType; + +import java.util.Collection; + +/** + * In expression. + */ +abstract public class UnaryInExpression extends UnaryExpression implements BooleanExpression { + + private boolean not; + + private Collection inList; + + public UnaryInExpression(Expression left, UnaryType unaryType, + Collection inList, boolean not) { + super(left, unaryType); + this.setInList(inList); + this.setNot(not); + + } + + public boolean matches(EvaluationContext context) throws Exception { + Object object = evaluate(context); + return object != null && object == Boolean.TRUE; + } + + public boolean isNot() { + return not; + } + + public void setNot(boolean not) { + this.not = not; + } + + public Collection getInList() { + return inList; + } + + public void setInList(Collection inList) { + this.inList = inList; + } +}; http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/parser/ParseException.java ---------------------------------------------------------------------- diff --git a/filter/src/main/java/org/apache/rocketmq/filter/parser/ParseException.java b/filter/src/main/java/org/apache/rocketmq/filter/parser/ParseException.java new file mode 100644 index 0000000..2ccccaf --- /dev/null +++ b/filter/src/main/java/org/apache/rocketmq/filter/parser/ParseException.java @@ -0,0 +1,204 @@ +/* + * 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. + */ + +/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 5.0 */ +/* JavaCCOptions:KEEP_LINE_COL=null */ +package org.apache.rocketmq.filter.parser; + +/** + * This exception is thrown when parse errors are encountered. + * You can explicitly create objects of this exception type by + * calling the method generateParseException in the generated + * parser. + * <p/> + * You can modify this class to customize your error reporting + * mechanisms so long as you retain the public fields. + */ +public class ParseException extends Exception { + + /** + * The version identifier for this Serializable class. + * Increment only if the <i>serialized</i> form of the + * class changes. + */ + private static final long serialVersionUID = 1L; + + /** + * This constructor is used by the method "generateParseException" + * in the generated parser. Calling this constructor generates + * a new object of this type with the fields "currentToken", + * "expectedTokenSequences", and "TOKEN_IMAGE" set. + */ + public ParseException(Token currentTokenVal, + int[][] expectedTokenSequencesVal, + String[] tokenImageVal + ) { + super(initialise(currentTokenVal, expectedTokenSequencesVal, tokenImageVal)); + currentToken = currentTokenVal; + expectedTokenSequences = expectedTokenSequencesVal; + tokenImage = tokenImageVal; + } + + /** + * The following constructors are for use by you for whatever + * purpose you can think of. Constructing the exception in this + * manner makes the exception behave in the normal way - i.e., as + * documented in the class "Throwable". The fields "errorToken", + * "expectedTokenSequences", and "TOKEN_IMAGE" do not contain + * relevant information. The JavaCC generated code does not use + * these constructors. + */ + + public ParseException() { + super(); + } + + /** + * Constructor with message. + */ + public ParseException(String message) { + super(message); + } + + /** + * This is the last token that has been consumed successfully. If + * this object has been created due to a parse error, the token + * followng this token will (therefore) be the first error token. + */ + public Token currentToken; + + /** + * Each entry in this array is an array of integers. Each array + * of integers represents a sequence of tokens (by their ordinal + * values) that is expected at this point of the parse. + */ + public int[][] expectedTokenSequences; + + /** + * This is a reference to the "TOKEN_IMAGE" array of the generated + * parser within which the parse error occurred. This array is + * defined in the generated ...Constants interface. + */ + public String[] tokenImage; + + /** + * It uses "currentToken" and "expectedTokenSequences" to generate a parse + * error message and returns it. If this object has been created + * due to a parse error, and you do not catch it (it gets thrown + * from the parser) the correct error message + * gets displayed. + */ + private static String initialise(Token currentToken, + int[][] expectedTokenSequences, + String[] tokenImage) { + String eol = System.getProperty("line.separator", "\n"); + StringBuffer expected = new StringBuffer(); + int maxSize = 0; + for (int i = 0; i < expectedTokenSequences.length; i++) { + if (maxSize < expectedTokenSequences[i].length) { + maxSize = expectedTokenSequences[i].length; + } + for (int j = 0; j < expectedTokenSequences[i].length; j++) { + expected.append(tokenImage[expectedTokenSequences[i][j]]).append(' '); + } + if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) { + expected.append("..."); + } + expected.append(eol).append(" "); + } + String retval = "Encountered \""; + Token tok = currentToken.next; + for (int i = 0; i < maxSize; i++) { + if (i != 0) + retval += " "; + if (tok.kind == 0) { + retval += tokenImage[0]; + break; + } + retval += " " + tokenImage[tok.kind]; + retval += " \""; + retval += add_escapes(tok.image); + retval += " \""; + tok = tok.next; + } + retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn; + retval += "." + eol; + if (expectedTokenSequences.length == 1) { + retval += "Was expecting:" + eol + " "; + } else { + retval += "Was expecting one of:" + eol + " "; + } + retval += expected.toString(); + return retval; + } + + /** + * The end of line string for this machine. + */ + protected String eol = System.getProperty("line.separator", "\n"); + + /** + * Used to convert raw characters to their escaped version + * when these raw version cannot be used as part of an ASCII + * string literal. + */ + static String add_escapes(String str) { + StringBuffer retval = new StringBuffer(); + char ch; + for (int i = 0; i < str.length(); i++) { + switch (str.charAt(i)) { + case 0: + continue; + case '\b': + retval.append("\\b"); + continue; + case '\t': + retval.append("\\t"); + continue; + case '\n': + retval.append("\\n"); + continue; + case '\f': + retval.append("\\f"); + continue; + case '\r': + retval.append("\\r"); + continue; + case '\"': + retval.append("\\\""); + continue; + case '\'': + retval.append("\\\'"); + continue; + case '\\': + retval.append("\\\\"); + continue; + default: + if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { + String s = "0000" + Integer.toString(ch, 16); + retval.append("\\u" + s.substring(s.length() - 4, s.length())); + } else { + retval.append(ch); + } + continue; + } + } + return retval.toString(); + } + +} +/* JavaCC - OriginalChecksum=4c829b0daa2c9af00ddafe2441eb9097 (do not edit this line) */ http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParser.java ---------------------------------------------------------------------- diff --git a/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParser.java b/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParser.java new file mode 100644 index 0000000..74e5501 --- /dev/null +++ b/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParser.java @@ -0,0 +1,1354 @@ +/* + * 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. + */ + +/* Generated By:JavaCC: Do not edit this line. SelectorParser.java */ +package org.apache.rocketmq.filter.parser; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import org.apache.rocketmq.filter.expression.BooleanExpression; +import org.apache.rocketmq.filter.expression.ComparisonExpression; +import org.apache.rocketmq.filter.expression.ConstantExpression; +import org.apache.rocketmq.filter.expression.Expression; +import org.apache.rocketmq.filter.expression.LogicExpression; +import org.apache.rocketmq.filter.expression.MQFilterException; +import org.apache.rocketmq.filter.expression.PropertyExpression; +import org.apache.rocketmq.filter.expression.UnaryExpression; + +import java.io.StringReader; +import java.util.ArrayList; + +/** + * JMS Selector Parser generated by JavaCC + * <p/> + * Do not edit this .java file directly - it is autogenerated from SelectorParser.jj + */ +public class SelectorParser implements SelectorParserConstants { + + private static final Cache<String, Object> PARSE_CACHE = CacheBuilder.newBuilder().maximumSize(100).build(); + // private static final String CONVERT_STRING_EXPRESSIONS_PREFIX = "convert_string_expressions:"; + + public static BooleanExpression parse(String sql) throws MQFilterException { + // sql = "("+sql+")"; + Object result = PARSE_CACHE.getIfPresent(sql); + if (result instanceof MQFilterException) { + throw (MQFilterException) result; + } else if (result instanceof BooleanExpression) { + return (BooleanExpression) result; + } else { + + // boolean convertStringExpressions = false; + // if( sql.startsWith(CONVERT_STRING_EXPRESSIONS_PREFIX)) { + // convertStringExpressions = true; + // sql = sql.substring(CONVERT_STRING_EXPRESSIONS_PREFIX.length()); + // } + // + // if( convertStringExpressions ) { + // ComparisonExpression.CONVERT_STRING_EXPRESSIONS.set(true); + // } + ComparisonExpression.CONVERT_STRING_EXPRESSIONS.set(true); + try { + + BooleanExpression e = new SelectorParser(sql).parse(); + PARSE_CACHE.put(sql, e); + return e; + } catch (MQFilterException t) { + PARSE_CACHE.put(sql, t); + throw t; + } finally { + ComparisonExpression.CONVERT_STRING_EXPRESSIONS.remove(); + // if( convertStringExpressions ) { + // ComparisonExpression.CONVERT_STRING_EXPRESSIONS.remove(); + // } + } + } + } + + public static void clearCache() { + PARSE_CACHE.cleanUp(); + } + + private String sql; + + protected SelectorParser(String sql) { + this(new StringReader(sql)); + this.sql = sql; + } + + protected BooleanExpression parse() throws MQFilterException { + try { + return this.JmsSelector(); + } catch (Throwable e) { + throw new MQFilterException("Invalid MessageSelector. ", e); + } + } + + private BooleanExpression asBooleanExpression(Expression value) throws ParseException { + if (value instanceof BooleanExpression) { + return (BooleanExpression) value; + } + if (value instanceof PropertyExpression) { + return UnaryExpression.createBooleanCast(value); + } + throw new ParseException("Expression will not result in a boolean value: " + value); + } + + // ---------------------------------------------------------------------------- + // Grammer + // ---------------------------------------------------------------------------- + final public BooleanExpression JmsSelector() throws ParseException { + Expression left = null; + left = orExpression(); + { + if (true) + return asBooleanExpression(left); + } + throw new Error("Missing return statement in function"); + } + + final public Expression orExpression() throws ParseException { + Expression left; + Expression right; + left = andExpression(); + label_1: + while (true) { + switch ((jjNtk == -1) ? jj_ntk() : jjNtk) { + case OR: + break; + default: + jjLa1[0] = jjGen; + break label_1; + } + jj_consume_token(OR); + right = andExpression(); + left = LogicExpression.createOR(asBooleanExpression(left), asBooleanExpression(right)); + } + { + if (true) + return left; + } + throw new Error("Missing return statement in function"); + } + + final public Expression andExpression() throws ParseException { + Expression left; + Expression right; + left = equalityExpression(); + label_2: + while (true) { + switch ((jjNtk == -1) ? jj_ntk() : jjNtk) { + case AND: + break; + default: + jjLa1[1] = jjGen; + break label_2; + } + jj_consume_token(AND); + right = equalityExpression(); + left = LogicExpression.createAND(asBooleanExpression(left), asBooleanExpression(right)); + } + { + if (true) + return left; + } + throw new Error("Missing return statement in function"); + } + + final public Expression equalityExpression() throws ParseException { + Expression left; + Expression right; + left = comparisonExpression(); + label_3: + while (true) { + switch ((jjNtk == -1) ? jj_ntk() : jjNtk) { + case IS: + case 22: + case 23: + break; + default: + jjLa1[2] = jjGen; + break label_3; + } + switch ((jjNtk == -1) ? jj_ntk() : jjNtk) { + case 22: + jj_consume_token(22); + right = comparisonExpression(); + left = ComparisonExpression.createEqual(left, right); + break; + case 23: + jj_consume_token(23); + right = comparisonExpression(); + left = ComparisonExpression.createNotEqual(left, right); + break; + default: + jjLa1[3] = jjGen; + if (jj_2_1(2)) { + jj_consume_token(IS); + jj_consume_token(NULL); + left = ComparisonExpression.createIsNull(left); + } else { + switch ((jjNtk == -1) ? jj_ntk() : jjNtk) { + case IS: + jj_consume_token(IS); + jj_consume_token(NOT); + jj_consume_token(NULL); + left = ComparisonExpression.createIsNotNull(left); + break; + default: + jjLa1[4] = jjGen; + jj_consume_token(-1); + throw new ParseException(); + } + } + } + } + { + if (true) + return left; + } + throw new Error("Missing return statement in function"); + } + + final public Expression comparisonExpression() throws ParseException { + Expression left; + Expression right; + Expression low; + Expression high; + String t, u; + boolean not; + ArrayList list; + left = unaryExpr(); + label_4: + while (true) { + switch ((jjNtk == -1) ? jj_ntk() : jjNtk) { + case NOT: + case BETWEEN: + case IN: + case 24: + case 25: + case 26: + case 27: + break; + default: + jjLa1[5] = jjGen; + break label_4; + } + switch ((jjNtk == -1) ? jj_ntk() : jjNtk) { + case 24: + jj_consume_token(24); + right = unaryExpr(); + left = ComparisonExpression.createGreaterThan(left, right); + break; + case 25: + jj_consume_token(25); + right = unaryExpr(); + left = ComparisonExpression.createGreaterThanEqual(left, right); + break; + case 26: + jj_consume_token(26); + right = unaryExpr(); + left = ComparisonExpression.createLessThan(left, right); + break; + case 27: + jj_consume_token(27); + right = unaryExpr(); + left = ComparisonExpression.createLessThanEqual(left, right); + break; + case BETWEEN: + jj_consume_token(BETWEEN); + low = unaryExpr(); + jj_consume_token(AND); + high = unaryExpr(); + left = ComparisonExpression.createBetween(left, low, high); + break; + default: + jjLa1[8] = jjGen; + if (jj_2_2(2)) { + jj_consume_token(NOT); + jj_consume_token(BETWEEN); + low = unaryExpr(); + jj_consume_token(AND); + high = unaryExpr(); + left = ComparisonExpression.createNotBetween(left, low, high); + } else { + switch ((jjNtk == -1) ? jj_ntk() : jjNtk) { + case IN: + jj_consume_token(IN); + jj_consume_token(28); + t = stringLitteral(); + list = new ArrayList(); + list.add(t); + label_5: + while (true) { + switch ((jjNtk == -1) ? jj_ntk() : jjNtk) { + case 29: + break; + default: + jjLa1[6] = jjGen; + break label_5; + } + jj_consume_token(29); + t = stringLitteral(); + list.add(t); + } + jj_consume_token(30); + left = ComparisonExpression.createInFilter(left, list); + break; + default: + jjLa1[9] = jjGen; + if (jj_2_3(2)) { + jj_consume_token(NOT); + jj_consume_token(IN); + jj_consume_token(28); + t = stringLitteral(); + list = new ArrayList(); + list.add(t); + label_6: + while (true) { + switch ((jjNtk == -1) ? jj_ntk() : jjNtk) { + case 29: + break; + default: + jjLa1[7] = jjGen; + break label_6; + } + jj_consume_token(29); + t = stringLitteral(); + list.add(t); + } + jj_consume_token(30); + left = ComparisonExpression.createNotInFilter(left, list); + } else { + jj_consume_token(-1); + throw new ParseException(); + } + } + } + } + } + { + if (true) + return left; + } + throw new Error("Missing return statement in function"); + } + + final public Expression unaryExpr() throws ParseException { + String s = null; + Expression left = null; + if (jj_2_4(2147483647)) { + jj_consume_token(31); + left = unaryExpr(); + } else { + switch ((jjNtk == -1) ? jj_ntk() : jjNtk) { + case 32: + jj_consume_token(32); + left = unaryExpr(); + left = UnaryExpression.createNegate(left); + break; + case NOT: + jj_consume_token(NOT); + left = unaryExpr(); + left = UnaryExpression.createNOT(asBooleanExpression(left)); + break; + case TRUE: + case FALSE: + case NULL: + case DECIMAL_LITERAL: + case FLOATING_POINT_LITERAL: + case STRING_LITERAL: + case ID: + case 28: + left = primaryExpr(); + break; + default: + jjLa1[10] = jjGen; + jj_consume_token(-1); + throw new ParseException(); + } + } + { + if (true) + return left; + } + throw new Error("Missing return statement in function"); + } + + final public Expression primaryExpr() throws ParseException { + Expression left = null; + switch ((jjNtk == -1) ? jj_ntk() : jjNtk) { + case TRUE: + case FALSE: + case NULL: + case DECIMAL_LITERAL: + case FLOATING_POINT_LITERAL: + case STRING_LITERAL: + left = literal(); + break; + case ID: + left = variable(); + break; + case 28: + jj_consume_token(28); + left = orExpression(); + jj_consume_token(30); + break; + default: + jjLa1[11] = jjGen; + jj_consume_token(-1); + throw new ParseException(); + } + { + if (true) + return left; + } + throw new Error("Missing return statement in function"); + } + + final public ConstantExpression literal() throws ParseException { + Token t; + String s; + ConstantExpression left = null; + switch ((jjNtk == -1) ? jj_ntk() : jjNtk) { + case STRING_LITERAL: + s = stringLitteral(); + left = new ConstantExpression(s); + break; + case DECIMAL_LITERAL: + t = jj_consume_token(DECIMAL_LITERAL); + left = ConstantExpression.createFromDecimal(t.image); + break; + case FLOATING_POINT_LITERAL: + t = jj_consume_token(FLOATING_POINT_LITERAL); + left = ConstantExpression.createFloat(t.image); + break; + case TRUE: + jj_consume_token(TRUE); + left = ConstantExpression.TRUE; + break; + case FALSE: + jj_consume_token(FALSE); + left = ConstantExpression.FALSE; + break; + case NULL: + jj_consume_token(NULL); + left = ConstantExpression.NULL; + break; + default: + jjLa1[12] = jjGen; + jj_consume_token(-1); + throw new ParseException(); + } + { + if (true) + return left; + } + throw new Error("Missing return statement in function"); + } + + final public String stringLitteral() throws ParseException { + Token t; + StringBuffer rc = new StringBuffer(); + boolean first = true; + t = jj_consume_token(STRING_LITERAL); + // Decode the sting value. + String image = t.image; + for (int i = 1; i < image.length() - 1; i++) { + char c = image.charAt(i); + if (c == '\'') + i++; + rc.append(c); + } + { + if (true) + return rc.toString(); + } + throw new Error("Missing return statement in function"); + } + + final public PropertyExpression variable() throws ParseException { + Token t; + PropertyExpression left = null; + t = jj_consume_token(ID); + left = new PropertyExpression(t.image); + { + if (true) + return left; + } + throw new Error("Missing return statement in function"); + } + + private boolean jj_2_1(int xla) { + jjLa = xla; + jjLastpos = jjScanpos = token; + try { + return !jj_3_1(); + } catch (LookaheadSuccess ls) { + return true; + } finally { + jj_save(0, xla); + } + } + + private boolean jj_2_2(int xla) { + jjLa = xla; + jjLastpos = jjScanpos = token; + try { + return !jj_3_2(); + } catch (LookaheadSuccess ls) { + return true; + } finally { + jj_save(1, xla); + } + } + + private boolean jj_2_3(int xla) { + jjLa = xla; + jjLastpos = jjScanpos = token; + try { + return !jj_3_3(); + } catch (LookaheadSuccess ls) { + return true; + } finally { + jj_save(2, xla); + } + } + + private boolean jj_2_4(int xla) { + jjLa = xla; + jjLastpos = jjScanpos = token; + try { + return !jj_3_4(); + } catch (LookaheadSuccess ls) { + return true; + } finally { + jj_save(3, xla); + } + } + + private boolean jj_3R_7() { + Token xsp; + xsp = jjScanpos; + if (jj_3R_8()) { + jjScanpos = xsp; + if (jj_3R_9()) { + jjScanpos = xsp; + if (jj_3R_10()) { + jjScanpos = xsp; + if (jj_3R_11()) + return true; + } + } + } + return false; + } + + private boolean jj_3R_43() { + if (jj_scan_token(29)) + return true; + if (jj_3R_27()) + return true; + return false; + } + + private boolean jj_3R_24() { + if (jj_scan_token(NULL)) + return true; + return false; + } + + private boolean jj_3R_35() { + if (jj_scan_token(IS)) + return true; + if (jj_scan_token(NOT)) + return true; + if (jj_scan_token(NULL)) + return true; + return false; + } + + private boolean jj_3_1() { + if (jj_scan_token(IS)) + return true; + if (jj_scan_token(NULL)) + return true; + return false; + } + + private boolean jj_3R_23() { + if (jj_scan_token(FALSE)) + return true; + return false; + } + + private boolean jj_3R_34() { + if (jj_scan_token(23)) + return true; + if (jj_3R_30()) + return true; + return false; + } + + private boolean jj_3R_22() { + if (jj_scan_token(TRUE)) + return true; + return false; + } + + private boolean jj_3_3() { + if (jj_scan_token(NOT)) + return true; + if (jj_scan_token(IN)) + return true; + if (jj_scan_token(28)) + return true; + if (jj_3R_27()) + return true; + Token xsp; + while (true) { + xsp = jjScanpos; + if (jj_3R_43()) { + jjScanpos = xsp; + break; + } + } + if (jj_scan_token(30)) + return true; + return false; + } + + private boolean jj_3R_31() { + Token xsp; + xsp = jjScanpos; + if (jj_3R_33()) { + jjScanpos = xsp; + if (jj_3R_34()) { + jjScanpos = xsp; + if (jj_3_1()) { + jjScanpos = xsp; + if (jj_3R_35()) + return true; + } + } + } + return false; + } + + private boolean jj_3R_33() { + if (jj_scan_token(22)) + return true; + if (jj_3R_30()) + return true; + return false; + } + + private boolean jj_3R_42() { + if (jj_scan_token(29)) + return true; + if (jj_3R_27()) + return true; + return false; + } + + private boolean jj_3R_21() { + if (jj_scan_token(FLOATING_POINT_LITERAL)) + return true; + return false; + } + + private boolean jj_3R_20() { + if (jj_scan_token(DECIMAL_LITERAL)) + return true; + return false; + } + + private boolean jj_3R_28() { + if (jj_3R_30()) + return true; + Token xsp; + while (true) { + xsp = jjScanpos; + if (jj_3R_31()) { + jjScanpos = xsp; + break; + } + } + return false; + } + + private boolean jj_3R_41() { + if (jj_scan_token(IN)) + return true; + if (jj_scan_token(28)) + return true; + if (jj_3R_27()) + return true; + Token xsp; + while (true) { + xsp = jjScanpos; + if (jj_3R_42()) { + jjScanpos = xsp; + break; + } + } + if (jj_scan_token(30)) + return true; + return false; + } + + private boolean jj_3R_19() { + if (jj_3R_27()) + return true; + return false; + } + + private boolean jj_3R_29() { + if (jj_scan_token(AND)) + return true; + if (jj_3R_28()) + return true; + return false; + } + + private boolean jj_3R_16() { + Token xsp; + xsp = jjScanpos; + if (jj_3R_19()) { + jjScanpos = xsp; + if (jj_3R_20()) { + jjScanpos = xsp; + if (jj_3R_21()) { + jjScanpos = xsp; + if (jj_3R_22()) { + jjScanpos = xsp; + if (jj_3R_23()) { + jjScanpos = xsp; + if (jj_3R_24()) + return true; + } + } + } + } + } + return false; + } + + private boolean jj_3_2() { + if (jj_scan_token(NOT)) + return true; + if (jj_scan_token(BETWEEN)) + return true; + if (jj_3R_7()) + return true; + if (jj_scan_token(AND)) + return true; + if (jj_3R_7()) + return true; + return false; + } + + private boolean jj_3R_40() { + if (jj_scan_token(BETWEEN)) + return true; + if (jj_3R_7()) + return true; + if (jj_scan_token(AND)) + return true; + if (jj_3R_7()) + return true; + return false; + } + + private boolean jj_3R_25() { + if (jj_3R_28()) + return true; + Token xsp; + while (true) { + xsp = jjScanpos; + if (jj_3R_29()) { + jjScanpos = xsp; + break; + } + } + return false; + } + + private boolean jj_3R_39() { + if (jj_scan_token(27)) + return true; + if (jj_3R_7()) + return true; + return false; + } + + private boolean jj_3R_15() { + if (jj_scan_token(28)) + return true; + if (jj_3R_18()) + return true; + if (jj_scan_token(30)) + return true; + return false; + } + + private boolean jj_3R_14() { + if (jj_3R_17()) + return true; + return false; + } + + private boolean jj_3R_38() { + if (jj_scan_token(26)) + return true; + if (jj_3R_7()) + return true; + return false; + } + + private boolean jj_3R_13() { + if (jj_3R_16()) + return true; + return false; + } + + private boolean jj_3R_26() { + if (jj_scan_token(OR)) + return true; + if (jj_3R_25()) + return true; + return false; + } + + private boolean jj_3R_17() { + if (jj_scan_token(ID)) + return true; + return false; + } + + private boolean jj_3R_37() { + if (jj_scan_token(25)) + return true; + if (jj_3R_7()) + return true; + return false; + } + + private boolean jj_3R_12() { + Token xsp; + xsp = jjScanpos; + if (jj_3R_13()) { + jjScanpos = xsp; + if (jj_3R_14()) { + jjScanpos = xsp; + if (jj_3R_15()) + return true; + } + } + return false; + } + + private boolean jj_3R_32() { + Token xsp; + xsp = jjScanpos; + if (jj_3R_36()) { + jjScanpos = xsp; + if (jj_3R_37()) { + jjScanpos = xsp; + if (jj_3R_38()) { + jjScanpos = xsp; + if (jj_3R_39()) { + jjScanpos = xsp; + if (jj_3R_40()) { + jjScanpos = xsp; + if (jj_3_2()) { + jjScanpos = xsp; + if (jj_3R_41()) { + jjScanpos = xsp; + if (jj_3_3()) + return true; + } + } + } + } + } + } + } + return false; + } + + private boolean jj_3R_36() { + if (jj_scan_token(24)) + return true; + if (jj_3R_7()) + return true; + return false; + } + + private boolean jj_3R_11() { + if (jj_3R_12()) + return true; + return false; + } + + private boolean jj_3R_18() { + if (jj_3R_25()) + return true; + Token xsp; + while (true) { + xsp = jjScanpos; + if (jj_3R_26()) { + jjScanpos = xsp; + break; + } + } + return false; + } + + private boolean jj_3_4() { + if (jj_scan_token(31)) + return true; + if (jj_3R_7()) + return true; + return false; + } + + private boolean jj_3R_10() { + if (jj_scan_token(NOT)) + return true; + if (jj_3R_7()) + return true; + return false; + } + + private boolean jj_3R_9() { + if (jj_scan_token(32)) + return true; + if (jj_3R_7()) + return true; + return false; + } + + private boolean jj_3R_27() { + if (jj_scan_token(STRING_LITERAL)) + return true; + return false; + } + + private boolean jj_3R_30() { + if (jj_3R_7()) + return true; + Token xsp; + while (true) { + xsp = jjScanpos; + if (jj_3R_32()) { + jjScanpos = xsp; + break; + } + } + return false; + } + + private boolean jj_3R_8() { + if (jj_scan_token(31)) + return true; + if (jj_3R_7()) + return true; + return false; + } + + /** + * Generated Token Manager. + */ + public SelectorParserTokenManager tokenSource; + SimpleCharStream jjInputStream; + /** + * Current token. + */ + public Token token; + /** + * Next token. + */ + public Token jjNt; + private int jjNtk; + private Token jjScanpos, jjLastpos; + private int jjLa; + private int jjGen; + final private int[] jjLa1 = new int[13]; + static private int[] jjLa10; + static private int[] jjLa11; + + static { + jj_la1_init_0(); + jj_la1_init_1(); + } + + private static void jj_la1_init_0() { + jjLa10 = new int[]{0x400, 0x200, 0xc10000, 0xc00000, 0x10000, 0xf001900, 0x20000000, 0x20000000, 0xf000800, + 0x1000, 0x1036e100, 0x1036e000, 0x16e000}; + } + + private static void jj_la1_init_1() { + jjLa11 = new int[]{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0}; + } + + final private JJCalls[] jj2Rtns = new JJCalls[4]; + private boolean jjRescan = false; + private int jjGc = 0; + + /** + * Constructor with InputStream. + */ + public SelectorParser(java.io.InputStream stream) { + this(stream, null); + } + + /** + * Constructor with InputStream and supplied encoding + */ + public SelectorParser(java.io.InputStream stream, String encoding) { + try { + jjInputStream = new SimpleCharStream(stream, encoding, 1, 1); + } catch (java.io.UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + tokenSource = new SelectorParserTokenManager(jjInputStream); + token = new Token(); + jjNtk = -1; + jjGen = 0; + for (int i = 0; i < 13; i++) + jjLa1[i] = -1; + for (int i = 0; i < jj2Rtns.length; i++) + jj2Rtns[i] = new JJCalls(); + } + + /** + * Reinitialise. + */ + public void ReInit(java.io.InputStream stream) { + ReInit(stream, null); + } + + /** + * Reinitialise. + */ + public void ReInit(java.io.InputStream stream, String encoding) { + try { + jjInputStream.ReInit(stream, encoding, 1, 1); + } catch (java.io.UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + tokenSource.ReInit(jjInputStream); + token = new Token(); + jjNtk = -1; + jjGen = 0; + for (int i = 0; i < 13; i++) + jjLa1[i] = -1; + for (int i = 0; i < jj2Rtns.length; i++) + jj2Rtns[i] = new JJCalls(); + } + + /** + * Constructor. + */ + public SelectorParser(java.io.Reader stream) { + jjInputStream = new SimpleCharStream(stream, 1, 1); + tokenSource = new SelectorParserTokenManager(jjInputStream); + token = new Token(); + jjNtk = -1; + jjGen = 0; + for (int i = 0; i < 13; i++) + jjLa1[i] = -1; + for (int i = 0; i < jj2Rtns.length; i++) + jj2Rtns[i] = new JJCalls(); + } + + /** + * Reinitialise. + */ + public void ReInit(java.io.Reader stream) { + jjInputStream.ReInit(stream, 1, 1); + tokenSource.ReInit(jjInputStream); + token = new Token(); + jjNtk = -1; + jjGen = 0; + for (int i = 0; i < 13; i++) + jjLa1[i] = -1; + for (int i = 0; i < jj2Rtns.length; i++) + jj2Rtns[i] = new JJCalls(); + } + + /** + * Constructor with generated Token Manager. + */ + public SelectorParser(SelectorParserTokenManager tm) { + tokenSource = tm; + token = new Token(); + jjNtk = -1; + jjGen = 0; + for (int i = 0; i < 13; i++) + jjLa1[i] = -1; + for (int i = 0; i < jj2Rtns.length; i++) + jj2Rtns[i] = new JJCalls(); + } + + /** + * Reinitialise. + */ + public void ReInit(SelectorParserTokenManager tm) { + tokenSource = tm; + token = new Token(); + jjNtk = -1; + jjGen = 0; + for (int i = 0; i < 13; i++) + jjLa1[i] = -1; + for (int i = 0; i < jj2Rtns.length; i++) + jj2Rtns[i] = new JJCalls(); + } + + private Token jj_consume_token(int kind) throws ParseException { + Token oldToken; + if ((oldToken = token).next != null) + token = token.next; + else + token = token.next = tokenSource.getNextToken(); + jjNtk = -1; + if (token.kind == kind) { + jjGen++; + if (++jjGc > 100) { + jjGc = 0; + for (int i = 0; i < jj2Rtns.length; i++) { + JJCalls c = jj2Rtns[i]; + while (c != null) { + if (c.gen < jjGen) + c.first = null; + c = c.next; + } + } + } + return token; + } + token = oldToken; + jjKind = kind; + throw generateParseException(); + } + + static private final class LookaheadSuccess extends java.lang.Error { + } + + final private LookaheadSuccess jjLs = new LookaheadSuccess(); + + private boolean jj_scan_token(int kind) { + if (jjScanpos == jjLastpos) { + jjLa--; + if (jjScanpos.next == null) { + jjLastpos = jjScanpos = jjScanpos.next = tokenSource.getNextToken(); + } else { + jjLastpos = jjScanpos = jjScanpos.next; + } + } else { + jjScanpos = jjScanpos.next; + } + if (jjRescan) { + int i = 0; + Token tok = token; + while (tok != null && tok != jjScanpos) { + i++; + tok = tok.next; + } + if (tok != null) + jj_add_error_token(kind, i); + } + if (jjScanpos.kind != kind) + return true; + if (jjLa == 0 && jjScanpos == jjLastpos) + throw jjLs; + return false; + } + + /** + * Get the next Token. + */ + final public Token getNextToken() { + if (token.next != null) + token = token.next; + else + token = token.next = tokenSource.getNextToken(); + jjNtk = -1; + jjGen++; + return token; + } + + /** + * Get the specific Token. + */ + final public Token getToken(int index) { + Token t = token; + for (int i = 0; i < index; i++) { + if (t.next != null) + t = t.next; + else + t = t.next = tokenSource.getNextToken(); + } + return t; + } + + private int jj_ntk() { + if ((jjNt = token.next) == null) + return jjNtk = (token.next = tokenSource.getNextToken()).kind; + else + return jjNtk = jjNt.kind; + } + + private java.util.List<int[]> jjExpentries = new java.util.ArrayList<int[]>(); + private int[] jjExpentry; + private int jjKind = -1; + private int[] jjLasttokens = new int[100]; + private int jjEndpos; + + private void jj_add_error_token(int kind, int pos) { + if (pos >= 100) + return; + if (pos == jjEndpos + 1) { + jjLasttokens[jjEndpos++] = kind; + } else if (jjEndpos != 0) { + jjExpentry = new int[jjEndpos]; + for (int i = 0; i < jjEndpos; i++) { + jjExpentry[i] = jjLasttokens[i]; + } + jj_entries_loop: + for (java.util.Iterator<?> it = jjExpentries.iterator(); it.hasNext(); ) { + int[] oldentry = (int[]) (it.next()); + if (oldentry.length == jjExpentry.length) { + for (int i = 0; i < jjExpentry.length; i++) { + if (oldentry[i] != jjExpentry[i]) { + continue jj_entries_loop; + } + } + jjExpentries.add(jjExpentry); + break jj_entries_loop; + } + } + if (pos != 0) + jjLasttokens[(jjEndpos = pos) - 1] = kind; + } + } + + /** + * Generate ParseException. + */ + public ParseException generateParseException() { + jjExpentries.clear(); + boolean[] la1tokens = new boolean[33]; + if (jjKind >= 0) { + la1tokens[jjKind] = true; + jjKind = -1; + } + for (int i = 0; i < 13; i++) { + if (jjLa1[i] == jjGen) { + for (int j = 0; j < 32; j++) { + if ((jjLa10[i] & (1 << j)) != 0) { + la1tokens[j] = true; + } + if ((jjLa11[i] & (1 << j)) != 0) { + la1tokens[32 + j] = true; + } + } + } + } + for (int i = 0; i < 33; i++) { + if (la1tokens[i]) { + jjExpentry = new int[1]; + jjExpentry[0] = i; + jjExpentries.add(jjExpentry); + } + } + jjEndpos = 0; + jj_rescan_token(); + jj_add_error_token(0, 0); + int[][] exptokseq = new int[jjExpentries.size()][]; + for (int i = 0; i < jjExpentries.size(); i++) { + exptokseq[i] = jjExpentries.get(i); + } + return new ParseException(token, exptokseq, TOKEN_IMAGE); + } + + /** + * Enable tracing. + */ + final public void enable_tracing() { + } + + /** + * Disable tracing. + */ + final public void disable_tracing() { + } + + private void jj_rescan_token() { + jjRescan = true; + for (int i = 0; i < 4; i++) { + try { + JJCalls p = jj2Rtns[i]; + do { + if (p.gen > jjGen) { + jjLa = p.arg; + jjLastpos = jjScanpos = p.first; + switch (i) { + case 0: + jj_3_1(); + break; + case 1: + jj_3_2(); + break; + case 2: + jj_3_3(); + break; + case 3: + jj_3_4(); + break; + } + } + p = p.next; + } while (p != null); + } catch (LookaheadSuccess ls) { + } + } + jjRescan = false; + } + + private void jj_save(int index, int xla) { + JJCalls p = jj2Rtns[index]; + while (p.gen > jjGen) { + if (p.next == null) { + p = p.next = new JJCalls(); + break; + } + p = p.next; + } + p.gen = jjGen + xla - jjLa; + p.first = token; + p.arg = xla; + } + + static final class JJCalls { + int gen; + Token first; + int arg; + JJCalls next; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParser.jj ---------------------------------------------------------------------- diff --git a/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParser.jj b/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParser.jj new file mode 100644 index 0000000..5d1a4a7 --- /dev/null +++ b/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParser.jj @@ -0,0 +1,524 @@ +/* + * 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. + */ + +/* + * This file was taken from ActiveMQ activemq-client/src/main/grammar/SelectorParser.jj. + * + * There are some modifications: + * 1. Convert string expressions default; + * 2. HEX_LITERAL and OCTAL_LITERAL were removed; + * 3. LIKE, ESCAPE, XPATH and XQUERY were removed; + * 4. Computation expressions were removed; + */ + +// ---------------------------------------------------------------------------- +// OPTIONS +// ---------------------------------------------------------------------------- +options { + STATIC = false; + UNICODE_INPUT = true; + + //ERROR_REPORTING = false; +} + +// ---------------------------------------------------------------------------- +// PARSER +// ---------------------------------------------------------------------------- + +PARSER_BEGIN(SelectorParser) + +package org.apache.rocketmq.filter.parser; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import org.apache.rocketmq.filter.expression.BooleanExpression; +import org.apache.rocketmq.filter.expression.ComparisonExpression; +import org.apache.rocketmq.filter.expression.ConstantExpression; +import org.apache.rocketmq.filter.expression.Expression; +import org.apache.rocketmq.filter.expression.LogicExpression; +import org.apache.rocketmq.filter.expression.MQFilterException; +import org.apache.rocketmq.filter.expression.PropertyExpression; +import org.apache.rocketmq.filter.expression.UnaryExpression; +import org.apache.rocketmq.filter.util.LRUCache; + +import java.io.StringReader; +import java.util.ArrayList; + +/** + * JMS Selector Parser generated by JavaCC + * + * Do not edit this .java file directly - it is autogenerated from SelectorParser.jj + */ +public class SelectorParser { + + private static final Cache<String, Object> PARSE_CACHE = CacheBuilder.newBuilder().maximumSize(100).build(); +// private static final String CONVERT_STRING_EXPRESSIONS_PREFIX = "convert_string_expressions:"; + + public static BooleanExpression parse(String sql) throws MQFilterException { +// sql = "("+sql+")"; + Object result = PARSE_CACHE.getIfPresent(sql); + if (result instanceof MQFilterException) { + throw (MQFilterException) result; + } else if (result instanceof BooleanExpression) { + return (BooleanExpression) result; + } else { + +// boolean convertStringExpressions = false; +// if( sql.startsWith(CONVERT_STRING_EXPRESSIONS_PREFIX)) { +// convertStringExpressions = true; +// sql = sql.substring(CONVERT_STRING_EXPRESSIONS_PREFIX.length()); +// } +// +// if( convertStringExpressions ) { +// ComparisonExpression.CONVERT_STRING_EXPRESSIONS.set(true); +// } + ComparisonExpression.CONVERT_STRING_EXPRESSIONS.set(true); + try { + + BooleanExpression e = new SelectorParser(sql).parse(); + PARSE_CACHE.put(sql, e); + return e; + } catch (MQFilterException t) { + PARSE_CACHE.put(sql, t); + throw t; + } finally { + ComparisonExpression.CONVERT_STRING_EXPRESSIONS.remove(); +// if( convertStringExpressions ) { +// ComparisonExpression.CONVERT_STRING_EXPRESSIONS.remove(); +// } + } + } + } + + public static void clearCache() { + PARSE_CACHE.cleanUp(); + } + + private String sql; + + protected SelectorParser(String sql) { + this(new StringReader(sql)); + this.sql = sql; + } + + protected BooleanExpression parse() throws MQFilterException { + try { + return this.JmsSelector(); + } + catch (Throwable e) { + throw new MQFilterException("Invalid MessageSelector. ", e); + } + } + + private BooleanExpression asBooleanExpression(Expression value) throws ParseException { + if (value instanceof BooleanExpression) { + return (BooleanExpression) value; + } + if (value instanceof PropertyExpression) { + return UnaryExpression.createBooleanCast( value ); + } + throw new ParseException("Expression will not result in a boolean value: " + value); + } + +} + +PARSER_END(SelectorParser) + +// ---------------------------------------------------------------------------- +// Tokens +// ---------------------------------------------------------------------------- + +/* White Space */ +SPECIAL_TOKEN : +{ + " " | "\t" | "\n" | "\r" | "\f" +} + +/* Comments */ +SKIP: +{ + <LINE_COMMENT: "--" (~["\n","\r"])* ("\n"|"\r"|"\r\n") > +} + +SKIP: +{ + <BLOCK_COMMENT: "/*" (~["*"])* "*" ("*" | (~["*","/"] (~["*"])* "*"))* "/"> +} + +/* Reserved Words */ +TOKEN [IGNORE_CASE] : +{ + < NOT : "NOT"> + | < AND : "AND"> + | < OR : "OR"> + | < BETWEEN : "BETWEEN"> + | < IN : "IN"> + | < TRUE : "TRUE" > + | < FALSE : "FALSE" > + | < NULL : "NULL" > + | < IS : "IS" > +} + +/* Literals */ +TOKEN [IGNORE_CASE] : + +{ + + < DECIMAL_LITERAL: "0" | ["1"-"9"] (["0"-"9"])* (["l","L"])? > + | < FLOATING_POINT_LITERAL: + (["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)? // matches: 5.5 or 5. or 5.5E10 or 5.E10 + | "." (["0"-"9"])+ (<EXPONENT>)? // matches: .5 or .5E10 + | (["0"-"9"])+ <EXPONENT> // matches: 5E10 + > + | < #EXPONENT: "E" (["+","-"])? (["0"-"9"])+ > + | < STRING_LITERAL: "'" ( ("''") | ~["'"] )* "'" > +} + +TOKEN [IGNORE_CASE] : +{ + < ID : ["a"-"z", "_", "$"] (["a"-"z","0"-"9","_", "$"])* > +} + +// ---------------------------------------------------------------------------- +// Grammer +// ---------------------------------------------------------------------------- +BooleanExpression JmsSelector() : +{ + Expression left=null; +} +{ + ( + left = orExpression() + ) + { + return asBooleanExpression(left); + } + +} + +Expression orExpression() : +{ + Expression left; + Expression right; +} +{ + ( + left = andExpression() + ( + <OR> right = andExpression() + { + left = LogicExpression.createOR(asBooleanExpression(left), asBooleanExpression(right)); + } + )* + ) + { + return left; + } + +} + + +Expression andExpression() : +{ + Expression left; + Expression right; +} +{ + ( + left = equalityExpression() + ( + <AND> right = equalityExpression() + { + left = LogicExpression.createAND(asBooleanExpression(left), asBooleanExpression(right)); + } + )* + ) + { + return left; + } +} + +Expression equalityExpression() : +{ + Expression left; + Expression right; +} +{ + ( + left = comparisonExpression() + ( + + "=" right = comparisonExpression() + { + left = ComparisonExpression.createEqual(left, right); + } + | + "<>" right = comparisonExpression() + { + left = ComparisonExpression.createNotEqual(left, right); + } + | + LOOKAHEAD(2) + <IS> <NULL> + { + left = ComparisonExpression.createIsNull(left); + } + | + <IS> <NOT> <NULL> + { + left = ComparisonExpression.createIsNotNull(left); + } + )* + ) + { + return left; + } +} + +Expression comparisonExpression() : +{ + Expression left; + Expression right; + Expression low; + Expression high; + String t, u; + boolean not; + ArrayList list; +} +{ + ( + left = unaryExpr() + ( + + ">" right = unaryExpr() + { + left = ComparisonExpression.createGreaterThan(left, right); + } + | + ">=" right = unaryExpr() + { + left = ComparisonExpression.createGreaterThanEqual(left, right); + } + | + "<" right = unaryExpr() + { + left = ComparisonExpression.createLessThan(left, right); + } + | + "<=" right = unaryExpr() + { + left = ComparisonExpression.createLessThanEqual(left, right); + } + | + <BETWEEN> low = unaryExpr() <AND> high = unaryExpr() + { + left = ComparisonExpression.createBetween(left, low, high); + } + | + LOOKAHEAD(2) + <NOT> <BETWEEN> low = unaryExpr() <AND> high = unaryExpr() + { + left = ComparisonExpression.createNotBetween(left, low, high); + } + | + <IN> + "(" + t = stringLitteral() + { + list = new ArrayList(); + list.add( t ); + } + ( + "," + t = stringLitteral() + { + list.add( t ); + } + + )* + ")" + { + left = ComparisonExpression.createInFilter(left, list); + } + | + LOOKAHEAD(2) + <NOT> <IN> + "(" + t = stringLitteral() + { + list = new ArrayList(); + list.add( t ); + } + ( + "," + t = stringLitteral() + { + list.add( t ); + } + + )* + ")" + { + left = ComparisonExpression.createNotInFilter(left, list); + } + + )* + ) + { + return left; + } +} + +Expression unaryExpr() : +{ + String s=null; + Expression left=null; +} +{ + ( + LOOKAHEAD( "+" unaryExpr() ) + "+" left=unaryExpr() + | + "-" left=unaryExpr() + { + left = UnaryExpression.createNegate(left); + } + | + <NOT> left=unaryExpr() + { + left = UnaryExpression.createNOT( asBooleanExpression(left) ); + } + | + left = primaryExpr() + ) + { + return left; + } + +} + +Expression primaryExpr() : +{ + Expression left=null; +} +{ + ( + left = literal() + | + left = variable() + | + "(" left = orExpression() ")" + ) + { + return left; + } +} + + + +ConstantExpression literal() : +{ + Token t; + String s; + ConstantExpression left=null; +} +{ + ( + ( + s = stringLitteral() + { + left = new ConstantExpression(s); + } + ) + | + ( + t = <DECIMAL_LITERAL> + { + left = ConstantExpression.createFromDecimal(t.image); + } + ) + | + ( + t = <FLOATING_POINT_LITERAL> + { + left = ConstantExpression.createFloat(t.image); + } + ) + | + ( + <TRUE> + { + left = ConstantExpression.TRUE; + } + ) + | + ( + <FALSE> + { + left = ConstantExpression.FALSE; + } + ) + | + ( + <NULL> + { + left = ConstantExpression.NULL; + } + ) + ) + { + return left; + } +} + +String stringLitteral() : +{ + Token t; + StringBuffer rc = new StringBuffer(); + boolean first=true; +} +{ + t = <STRING_LITERAL> + { + // Decode the sting value. + String image = t.image; + for( int i=1; i < image.length()-1; i++ ) { + char c = image.charAt(i); + if( c == '\'' ) + i++; + rc.append(c); + } + return rc.toString(); + } +} + +PropertyExpression variable() : +{ + Token t; + PropertyExpression left=null; +} +{ + ( + t = <ID> + { + left = new PropertyExpression(t.image); + } + ) + { + return left; + } +}