You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rocketmq.apache.org by do...@apache.org on 2017/06/06 03:38:43 UTC
[23/51] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-121]Support
message filtering based on SQL92 closes apache/incubator-rocketmq#82
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/9eeb2f7e/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/9eeb2f7e/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/9eeb2f7e/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/9eeb2f7e/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/9eeb2f7e/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/9eeb2f7e/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/9eeb2f7e/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/9eeb2f7e/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/9eeb2f7e/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/9eeb2f7e/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;
+ }
+}