You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by ch...@apache.org on 2009/06/01 06:05:38 UTC

svn commit: r780558 [2/3] - in /activemq/sandbox/activemq-flow: ./ activemq-all/ activemq-all/.settings/ activemq-all/eclipse-classes/ activemq-all/target/ activemq-broker/ activemq-broker/src/main/java/org/apache/activemq/broker/ activemq-broker/src/m...

Added: activemq/sandbox/activemq-flow/activemq-selector/src/main/grammar/SelectorParser.jj
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-selector/src/main/grammar/SelectorParser.jj?rev=780558&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-selector/src/main/grammar/SelectorParser.jj (added)
+++ activemq/sandbox/activemq-flow/activemq-selector/src/main/grammar/SelectorParser.jj Mon Jun  1 04:05:34 2009
@@ -0,0 +1,609 @@
+/**
+ * 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.
+ */
+
+// ----------------------------------------------------------------------------
+// OPTIONS
+// ----------------------------------------------------------------------------
+options {
+  STATIC = false;
+  UNICODE_INPUT = true;
+  
+  // some performance optimizations
+  OPTIMIZE_TOKEN_MANAGER = true;
+  ERROR_REPORTING = false;
+}
+
+// ----------------------------------------------------------------------------
+// PARSER
+// ----------------------------------------------------------------------------
+
+PARSER_BEGIN(SelectorParser)
+/**
+ * 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.activemq.selector;
+
+import java.io.*;
+import java.util.*;
+
+import org.apache.activemq.filter.*;
+import org.apache.activemq.util.LRUCache;
+
+/** 
+ * 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 LRUCache cache = new LRUCache(100);
+
+    public static BooleanExpression parse(String sql) throws FilterException {
+        Object result = cache.get(sql);
+        if (result instanceof FilterException) {
+            throw (FilterException) result;
+        } else if (result instanceof BooleanExpression) {
+            return (BooleanExpression) result;
+        } else {
+            try {
+                BooleanExpression e = new SelectorParser(sql).parse();
+                cache.put(sql, e);
+                return e;
+            } catch (FilterException t) {
+                cache.put(sql, t);
+                throw t;
+            }
+        }
+    }
+
+    public static void clearCache() {
+        cache.clear();
+    }
+
+    private String sql;
+
+    protected SelectorParser(String sql) {
+        this(new StringReader(sql));
+        this.sql = sql;
+    }
+
+    protected BooleanExpression parse() throws FilterException {
+        try {
+            return this.JmsSelector();
+        }
+        catch (Throwable e) {
+            throw new FilterException(sql, 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">
+  | <  LIKE    : "LIKE">
+  | <  ESCAPE  : "ESCAPE">
+  | <  IN      : "IN">
+  | <  IS      : "IS">
+  | <  TRUE    : "TRUE" >
+  | <  FALSE   : "FALSE" >
+  | <  NULL    : "NULL" >
+  | <  XPATH   : "XPATH" >
+  | <  XQUERY  : "XQUERY" >
+}
+
+/* Literals */
+TOKEN [IGNORE_CASE] :
+{
+
+    < DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* (["l","L"])? >
+  | < HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ >
+  | < OCTAL_LITERAL: "0" (["0"-"7"])* >  
+  | < 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 = addExpression() 
+        ( 
+            
+                ">" right = addExpression() 
+                {
+                    left = ComparisonExpression.createGreaterThan(left, right);
+                }
+            |            
+                ">=" right = addExpression() 
+                {
+                    left = ComparisonExpression.createGreaterThanEqual(left, right);
+                }
+            |            
+                "<" right = addExpression() 
+                {
+                    left = ComparisonExpression.createLessThan(left, right);
+                }
+            |            
+                "<=" right = addExpression() 
+                {
+                    left = ComparisonExpression.createLessThanEqual(left, right);
+                }
+           |
+				{
+					u=null;
+				}           		
+		        <LIKE> t = stringLitteral() 
+		        	[ <ESCAPE> u = stringLitteral() ]
+		        {
+                    left = ComparisonExpression.createLike(left, t, u);
+		        }
+           |
+	        	LOOKAHEAD(2)
+				{
+					u=null;
+				}           		
+		        <NOT> <LIKE> t = stringLitteral() [ <ESCAPE> u = stringLitteral() ]
+		        {
+                    left = ComparisonExpression.createNotLike(left, t, u);
+		        }
+            |
+		        <BETWEEN> low = addExpression() <AND> high = addExpression()
+		        {
+					left = ComparisonExpression.createBetween(left, low, high);
+		        }
+	        |
+	        	LOOKAHEAD(2)
+		        <NOT> <BETWEEN> low = addExpression() <AND> high = addExpression()
+		        {
+					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 addExpression() :
+{
+    Expression left;
+    Expression right;
+}
+{
+    left = multExpr() 
+    ( 
+	    LOOKAHEAD( ("+"|"-") multExpr())
+	    (
+	        "+" right = multExpr() 
+	        {
+	            left = ArithmeticExpression.createPlus(left, right);
+	        }
+	        |            
+	        "-" right = multExpr() 
+	        {
+	            left = ArithmeticExpression.createMinus(left, right);
+	        }
+        )
+        
+    )*
+    {
+        return left;
+    }
+}
+
+Expression multExpr() :
+{
+    Expression left;
+    Expression right;
+}
+{
+    left = unaryExpr() 
+    ( 
+        "*" right = unaryExpr() 
+        {
+	        left = ArithmeticExpression.createMultiply(left, right);
+        }
+        |            
+        "/" right = unaryExpr() 
+        {
+	        left = ArithmeticExpression.createDivide(left, right);
+        }
+        |            
+        "%" right = unaryExpr() 
+        {
+	        left = ArithmeticExpression.createMod(left, right);
+        }
+        
+    )*
+    {
+        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) );
+	    }
+	    |
+	    <XPATH> s=stringLitteral()
+	    {
+		    left = UnaryExpression.createXPath( s );
+	    }
+	    |
+	    <XQUERY> s=stringLitteral()
+	    {
+		    left = UnaryExpression.createXQuery( s );
+	    }
+	    |
+	    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 = <HEX_LITERAL>
+            {
+            	left = ConstantExpression.createFromHex(t.image);
+            }    
+        ) 
+        | 
+        (
+            t = <OCTAL_LITERAL>
+            {
+            	left = ConstantExpression.createFromOctal(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;
+    }
+}

Propchange: activemq/sandbox/activemq-flow/activemq-selector/src/main/grammar/SelectorParser.jj
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/ArithmeticExpression.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/ArithmeticExpression.java?rev=780558&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/ArithmeticExpression.java (added)
+++ activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/ArithmeticExpression.java Mon Jun  1 04:05:34 2009
@@ -0,0 +1,203 @@
+/**
+ * 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.activemq.filter;
+
+
+/**
+ * An expression which performs an operation on two expression values
+ * 
+ * @version $Revision: 1.2 $
+ */
+public abstract class ArithmeticExpression extends BinaryExpression {
+
+    protected static final int INTEGER = 1;
+    protected static final int LONG = 2;
+    protected static final int DOUBLE = 3;
+
+    /**
+     * @param left
+     * @param right
+     */
+    public ArithmeticExpression(Expression left, Expression right) {
+        super(left, right);
+    }
+
+    public static Expression createPlus(Expression left, Expression right) {
+        return new ArithmeticExpression(left, right) {
+            protected Object evaluate(Object lvalue, Object rvalue) {
+                if (lvalue instanceof String) {
+                    String text = (String)lvalue;
+                    String answer = text + rvalue;
+                    return answer;
+                } else if (lvalue instanceof Number) {
+                    return plus((Number)lvalue, asNumber(rvalue));
+                }
+                throw new RuntimeException("Cannot call plus operation on: " + lvalue + " and: " + rvalue);
+            }
+
+            public String getExpressionSymbol() {
+                return "+";
+            }
+        };
+    }
+
+    public static Expression createMinus(Expression left, Expression right) {
+        return new ArithmeticExpression(left, right) {
+            protected Object evaluate(Object lvalue, Object rvalue) {
+                if (lvalue instanceof Number) {
+                    return minus((Number)lvalue, asNumber(rvalue));
+                }
+                throw new RuntimeException("Cannot call minus operation on: " + lvalue + " and: " + rvalue);
+            }
+
+            public String getExpressionSymbol() {
+                return "-";
+            }
+        };
+    }
+
+    public static Expression createMultiply(Expression left, Expression right) {
+        return new ArithmeticExpression(left, right) {
+
+            protected Object evaluate(Object lvalue, Object rvalue) {
+                if (lvalue instanceof Number) {
+                    return multiply((Number)lvalue, asNumber(rvalue));
+                }
+                throw new RuntimeException("Cannot call multiply operation on: " + lvalue + " and: " + rvalue);
+            }
+
+            public String getExpressionSymbol() {
+                return "*";
+            }
+        };
+    }
+
+    public static Expression createDivide(Expression left, Expression right) {
+        return new ArithmeticExpression(left, right) {
+
+            protected Object evaluate(Object lvalue, Object rvalue) {
+                if (lvalue instanceof Number) {
+                    return divide((Number)lvalue, asNumber(rvalue));
+                }
+                throw new RuntimeException("Cannot call divide operation on: " + lvalue + " and: " + rvalue);
+            }
+
+            public String getExpressionSymbol() {
+                return "/";
+            }
+        };
+    }
+
+    public static Expression createMod(Expression left, Expression right) {
+        return new ArithmeticExpression(left, right) {
+
+            protected Object evaluate(Object lvalue, Object rvalue) {
+                if (lvalue instanceof Number) {
+                    return mod((Number)lvalue, asNumber(rvalue));
+                }
+                throw new RuntimeException("Cannot call mod operation on: " + lvalue + " and: " + rvalue);
+            }
+
+            public String getExpressionSymbol() {
+                return "%";
+            }
+        };
+    }
+
+    protected Number plus(Number left, Number right) {
+        switch (numberType(left, right)) {
+        case INTEGER:
+            return new Integer(left.intValue() + right.intValue());
+        case LONG:
+            return new Long(left.longValue() + right.longValue());
+        default:
+            return new Double(left.doubleValue() + right.doubleValue());
+        }
+    }
+
+    protected Number minus(Number left, Number right) {
+        switch (numberType(left, right)) {
+        case INTEGER:
+            return new Integer(left.intValue() - right.intValue());
+        case LONG:
+            return new Long(left.longValue() - right.longValue());
+        default:
+            return new Double(left.doubleValue() - right.doubleValue());
+        }
+    }
+
+    protected Number multiply(Number left, Number right) {
+        switch (numberType(left, right)) {
+        case INTEGER:
+            return new Integer(left.intValue() * right.intValue());
+        case LONG:
+            return new Long(left.longValue() * right.longValue());
+        default:
+            return new Double(left.doubleValue() * right.doubleValue());
+        }
+    }
+
+    protected Number divide(Number left, Number right) {
+        return new Double(left.doubleValue() / right.doubleValue());
+    }
+
+    protected Number mod(Number left, Number right) {
+        return new Double(left.doubleValue() % right.doubleValue());
+    }
+
+    private int numberType(Number left, Number right) {
+        if (isDouble(left) || isDouble(right)) {
+            return DOUBLE;
+        } else if (left instanceof Long || right instanceof Long) {
+            return LONG;
+        } else {
+            return INTEGER;
+        }
+    }
+
+    private boolean isDouble(Number n) {
+        return n instanceof Float || n instanceof Double;
+    }
+
+    protected Number asNumber(Object value) {
+        if (value instanceof Number) {
+            return (Number)value;
+        } else {
+            throw new RuntimeException("Cannot convert value: " + value + " into a number");
+        }
+    }
+
+    public Object evaluate(MessageEvaluationContext message) throws FilterException {
+        Object lvalue = left.evaluate(message);
+        if (lvalue == null) {
+            return null;
+        }
+        Object rvalue = right.evaluate(message);
+        if (rvalue == null) {
+            return null;
+        }
+        return evaluate(lvalue, rvalue);
+    }
+
+    /**
+     * @param lvalue
+     * @param rvalue
+     * @return
+     */
+    protected abstract Object evaluate(Object lvalue, Object rvalue);
+
+}

Propchange: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/ArithmeticExpression.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/BinaryExpression.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/BinaryExpression.java?rev=780558&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/BinaryExpression.java (added)
+++ activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/BinaryExpression.java Mon Jun  1 04:05:34 2009
@@ -0,0 +1,96 @@
+/**
+ * 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.activemq.filter;
+
+
+
+/**
+ * An expression which performs an operation on two expression values.
+ * 
+ * @version $Revision: 1.2 $
+ */
+public abstract class BinaryExpression implements Expression {
+    protected Expression left;
+    protected Expression right;
+
+    public BinaryExpression(Expression left, Expression right) {
+        this.left = left;
+        this.right = right;
+    }
+
+    public Expression getLeft() {
+        return left;
+    }
+
+    public Expression getRight() {
+        return right;
+    }
+
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString() {
+        return "(" + left.toString() + " " + getExpressionSymbol() + " " + right.toString() + ")";
+    }
+
+    /**
+     * TODO: more efficient hashCode()
+     *
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode() {
+        return toString().hashCode();
+    }
+
+    /**
+     * TODO: more efficient hashCode()
+     *
+     * @see java.lang.Object#equals(java.lang.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();
+
+    /**
+     * @param expression
+     */
+    public void setRight(Expression expression) {
+        right = expression;
+    }
+
+    /**
+     * @param expression
+     */
+    public void setLeft(Expression expression) {
+        left = expression;
+    }
+    
+}

Propchange: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/BinaryExpression.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/BooleanExpression.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/BooleanExpression.java?rev=780558&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/BooleanExpression.java (added)
+++ activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/BooleanExpression.java Mon Jun  1 04:05:34 2009
@@ -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.activemq.filter;
+
+
+
+/**
+ * A BooleanExpression is an expression that always
+ * produces a Boolean result.
+ *
+ * @version $Revision: 1.2 $
+ */
+public interface BooleanExpression extends Expression {
+    
+    /**
+     * @param message
+     * @return true if the expression evaluates to Boolean.TRUE.
+     * @throws FilterException
+     */
+    boolean matches(MessageEvaluationContext message) throws FilterException;
+
+}

Propchange: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/BooleanExpression.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/ComparisonExpression.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/ComparisonExpression.java?rev=780558&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/ComparisonExpression.java (added)
+++ activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/ComparisonExpression.java Mon Jun  1 04:05:34 2009
@@ -0,0 +1,433 @@
+/**
+ * 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.activemq.filter;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+
+/**
+ * A filter performing a comparison of two objects
+ * 
+ * @version $Revision: 1.2 $
+ */
+public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression {
+
+    private static final Set<Character> REGEXP_CONTROL_CHARS = new HashSet<Character>();
+
+    /**
+     * @param left
+     * @param right
+     */
+    public ComparisonExpression(Expression left, Expression right) {
+        super(left, right);
+    }
+
+    public static BooleanExpression createBetween(Expression value, Expression left, Expression right) {
+        return LogicExpression.createAND(createGreaterThanEqual(value, left), createLessThanEqual(value, right));
+    }
+
+    public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right) {
+        return LogicExpression.createOR(createLessThan(value, left), createGreaterThan(value, right));
+    }
+
+    static {
+        REGEXP_CONTROL_CHARS.add(Character.valueOf('.'));
+        REGEXP_CONTROL_CHARS.add(Character.valueOf('\\'));
+        REGEXP_CONTROL_CHARS.add(Character.valueOf('['));
+        REGEXP_CONTROL_CHARS.add(Character.valueOf(']'));
+        REGEXP_CONTROL_CHARS.add(Character.valueOf('^'));
+        REGEXP_CONTROL_CHARS.add(Character.valueOf('$'));
+        REGEXP_CONTROL_CHARS.add(Character.valueOf('?'));
+        REGEXP_CONTROL_CHARS.add(Character.valueOf('*'));
+        REGEXP_CONTROL_CHARS.add(Character.valueOf('+'));
+        REGEXP_CONTROL_CHARS.add(Character.valueOf('{'));
+        REGEXP_CONTROL_CHARS.add(Character.valueOf('}'));
+        REGEXP_CONTROL_CHARS.add(Character.valueOf('|'));
+        REGEXP_CONTROL_CHARS.add(Character.valueOf('('));
+        REGEXP_CONTROL_CHARS.add(Character.valueOf(')'));
+        REGEXP_CONTROL_CHARS.add(Character.valueOf(':'));
+        REGEXP_CONTROL_CHARS.add(Character.valueOf('&'));
+        REGEXP_CONTROL_CHARS.add(Character.valueOf('<'));
+        REGEXP_CONTROL_CHARS.add(Character.valueOf('>'));
+        REGEXP_CONTROL_CHARS.add(Character.valueOf('='));
+        REGEXP_CONTROL_CHARS.add(Character.valueOf('!'));
+    }
+
+    static class LikeExpression extends UnaryExpression implements BooleanExpression {
+
+        Pattern likePattern;
+
+        /**
+         * @param left
+         */
+        public LikeExpression(Expression right, String like, int escape) {
+            super(right);
+
+            StringBuffer regexp = new StringBuffer(like.length() * 2);
+            regexp.append("\\A"); // The beginning of the input
+            for (int i = 0; i < like.length(); i++) {
+                char c = like.charAt(i);
+                if (escape == (0xFFFF & c)) {
+                    i++;
+                    if (i >= like.length()) {
+                        // nothing left to escape...
+                        break;
+                    }
+
+                    char t = like.charAt(i);
+                    regexp.append("\\x");
+                    regexp.append(Integer.toHexString(0xFFFF & t));
+                } else if (c == '%') {
+                    regexp.append(".*?"); // Do a non-greedy match
+                } else if (c == '_') {
+                    regexp.append("."); // match one
+                } else if (REGEXP_CONTROL_CHARS.contains(new Character(c))) {
+                    regexp.append("\\x");
+                    regexp.append(Integer.toHexString(0xFFFF & c));
+                } else {
+                    regexp.append(c);
+                }
+            }
+            regexp.append("\\z"); // The end of the input
+
+            likePattern = Pattern.compile(regexp.toString(), Pattern.DOTALL);
+        }
+
+        /**
+         * @see org.apache.activemq.filter.UnaryExpression#getExpressionSymbol()
+         */
+        public String getExpressionSymbol() {
+            return "LIKE";
+        }
+
+        /**
+         * @see org.apache.activemq.filter.Expression#evaluate(MessageEvaluationContext)
+         */
+        public Object evaluate(MessageEvaluationContext message) throws FilterException {
+
+            Object rv = this.getRight().evaluate(message);
+
+            if (rv == null) {
+                return null;
+            }
+
+            if (!(rv instanceof String)) {
+                return Boolean.FALSE;
+                // throw new RuntimeException("LIKE can only operate on String
+                // identifiers. LIKE attemped on: '" + rv.getClass());
+            }
+
+            return likePattern.matcher((String)rv).matches() ? Boolean.TRUE : Boolean.FALSE;
+        }
+
+        public boolean matches(MessageEvaluationContext message) throws FilterException {
+            Object object = evaluate(message);
+            return object != null && object == Boolean.TRUE;
+        }
+    }
+
+    public static BooleanExpression createLike(Expression left, String right, String escape) {
+        if (escape != null && escape.length() != 1) {
+            throw new RuntimeException("The ESCAPE string litteral is invalid.  It can only be one character.  Litteral used: " + escape);
+        }
+        int c = -1;
+        if (escape != null) {
+            c = 0xFFFF & escape.charAt(0);
+        }
+
+        return new LikeExpression(left, right, c);
+    }
+
+    public static BooleanExpression createNotLike(Expression left, String right, String escape) {
+        return UnaryExpression.createNOT(createLike(left, right, escape));
+    }
+
+    public static BooleanExpression createInFilter(Expression left, List elements) {
+
+        if (!(left instanceof PropertyExpression)) {
+            throw new RuntimeException("Expected a property for In expression, got: " + left);
+        }
+        return UnaryExpression.createInExpression((PropertyExpression)left, elements, false);
+
+    }
+
+    public static BooleanExpression createNotInFilter(Expression left, List elements) {
+
+        if (!(left instanceof PropertyExpression)) {
+            throw new RuntimeException("Expected a property for In expression, got: " + left);
+        }
+        return UnaryExpression.createInExpression((PropertyExpression)left, elements, true);
+
+    }
+
+    public static BooleanExpression createIsNull(Expression left) {
+        return doCreateEqual(left, ConstantExpression.NULL);
+    }
+
+    public static BooleanExpression createIsNotNull(Expression left) {
+        return UnaryExpression.createNOT(doCreateEqual(left, ConstantExpression.NULL));
+    }
+
+    public static BooleanExpression createNotEqual(Expression left, Expression right) {
+        return UnaryExpression.createNOT(createEqual(left, right));
+    }
+
+    public static BooleanExpression createEqual(Expression left, Expression right) {
+        checkEqualOperand(left);
+        checkEqualOperand(right);
+        checkEqualOperandCompatability(left, right);
+        return doCreateEqual(left, right);
+    }
+
+    private static BooleanExpression doCreateEqual(Expression left, Expression right) {
+        return new ComparisonExpression(left, right) {
+
+            public Object evaluate(MessageEvaluationContext message) throws FilterException {
+                Object lv = left.evaluate(message);
+                Object rv = right.evaluate(message);
+
+                // Iff one of the values is null
+                if (lv == null ^ rv == null) {
+                    return Boolean.FALSE;
+                }
+                if (lv == rv || lv.equals(rv)) {
+                    return Boolean.TRUE;
+                }
+                if (lv instanceof Comparable && rv instanceof Comparable) {
+                    return compare((Comparable)lv, (Comparable)rv);
+                }
+                return Boolean.FALSE;
+            }
+
+            protected boolean asBoolean(int answer) {
+                return answer == 0;
+            }
+
+            public String getExpressionSymbol() {
+                return "=";
+            }
+        };
+    }
+
+    public static BooleanExpression createGreaterThan(final Expression left, final Expression right) {
+        checkLessThanOperand(left);
+        checkLessThanOperand(right);
+        return new ComparisonExpression(left, right) {
+            protected boolean asBoolean(int answer) {
+                return answer > 0;
+            }
+
+            public String getExpressionSymbol() {
+                return ">";
+            }
+        };
+    }
+
+    public static BooleanExpression createGreaterThanEqual(final Expression left, final Expression right) {
+        checkLessThanOperand(left);
+        checkLessThanOperand(right);
+        return new ComparisonExpression(left, right) {
+            protected boolean asBoolean(int answer) {
+                return answer >= 0;
+            }
+
+            public String getExpressionSymbol() {
+                return ">=";
+            }
+        };
+    }
+
+    public static BooleanExpression createLessThan(final Expression left, final Expression right) {
+        checkLessThanOperand(left);
+        checkLessThanOperand(right);
+        return new ComparisonExpression(left, right) {
+
+            protected boolean asBoolean(int answer) {
+                return answer < 0;
+            }
+
+            public String getExpressionSymbol() {
+                return "<";
+            }
+
+        };
+    }
+
+    public static BooleanExpression createLessThanEqual(final Expression left, final Expression right) {
+        checkLessThanOperand(left);
+        checkLessThanOperand(right);
+        return new ComparisonExpression(left, right) {
+
+            protected boolean asBoolean(int answer) {
+                return answer <= 0;
+            }
+
+            public String getExpressionSymbol() {
+                return "<=";
+            }
+        };
+    }
+
+    /**
+     * Only Numeric expressions can be used in >, >=, < or <= expressions.s
+     * 
+     * @param expr
+     */
+    public static void checkLessThanOperand(Expression expr) {
+        if (expr instanceof ConstantExpression) {
+            Object value = ((ConstantExpression)expr).getValue();
+            if (value instanceof Number) {
+                return;
+            }
+
+            // Else it's boolean or a String..
+            throw new RuntimeException("Value '" + expr + "' cannot be compared.");
+        }
+        if (expr instanceof BooleanExpression) {
+            throw new RuntimeException("Value '" + expr + "' cannot be compared.");
+        }
+    }
+
+    /**
+     * Validates that the expression can be used in == or <> expression. Cannot
+     * not be NULL TRUE or FALSE litterals.
+     * 
+     * @param expr
+     */
+    public static void checkEqualOperand(Expression expr) {
+        if (expr instanceof ConstantExpression) {
+            Object value = ((ConstantExpression)expr).getValue();
+            if (value == null) {
+                throw new RuntimeException("'" + expr + "' cannot be compared.");
+            }
+        }
+    }
+
+    /**
+     * @param left
+     * @param right
+     */
+    private static void checkEqualOperandCompatability(Expression left, Expression right) {
+        if (left instanceof ConstantExpression && right instanceof ConstantExpression) {
+            if (left instanceof BooleanExpression && !(right instanceof BooleanExpression)) {
+                throw new RuntimeException("'" + left + "' cannot be compared with '" + right + "'");
+            }
+        }
+    }
+
+    public Object evaluate(MessageEvaluationContext message) throws FilterException {
+        Comparable<Comparable> lv = (Comparable)left.evaluate(message);
+        if (lv == null) {
+            return null;
+        }
+        Comparable rv = (Comparable)right.evaluate(message);
+        if (rv == null) {
+            return null;
+        }
+        return compare(lv, rv);
+    }
+
+    protected Boolean compare(Comparable lv, Comparable rv) {
+        Class<? extends Comparable> lc = lv.getClass();
+        Class<? extends Comparable> rc = rv.getClass();
+        // If the the objects are not of the same type,
+        // try to convert up to allow the comparison.
+        if (lc != rc) {
+            if (lc == Byte.class) {
+                if (rc == Short.class) {
+                    lv = Short.valueOf(((Number)lv).shortValue());
+                } else if (rc == Integer.class) {
+                    lv = Integer.valueOf(((Number)lv).intValue());
+                } else if (rc == Long.class) {
+                    lv = Long.valueOf(((Number)lv).longValue());
+                } else if (rc == Float.class) {
+                    lv = new Float(((Number)lv).floatValue());
+                } else if (rc == Double.class) {
+                    lv = new Double(((Number)lv).doubleValue());
+                } else {
+                    return Boolean.FALSE;
+                }
+            } else if (lc == Short.class) {
+                if (rc == Integer.class) {
+                    lv = Integer.valueOf(((Number)lv).intValue());
+                } else if (rc == Long.class) {
+                    lv = Long.valueOf(((Number)lv).longValue());
+                } else if (rc == Float.class) {
+                    lv = new Float(((Number)lv).floatValue());
+                } else if (rc == Double.class) {
+                    lv = new Double(((Number)lv).doubleValue());
+                } else {
+                    return Boolean.FALSE;
+                }
+            } else if (lc == Integer.class) {
+                if (rc == Long.class) {
+                    lv = Long.valueOf(((Number)lv).longValue());
+                } else if (rc == Float.class) {
+                    lv = new Float(((Number)lv).floatValue());
+                } else if (rc == Double.class) {
+                    lv = new Double(((Number)lv).doubleValue());
+                } else {
+                    return Boolean.FALSE;
+                }
+            } else if (lc == Long.class) {
+                if (rc == Integer.class) {
+                    rv = Long.valueOf(((Number)rv).longValue());
+                } else if (rc == Float.class) {
+                    lv = new Float(((Number)lv).floatValue());
+                } else if (rc == Double.class) {
+                    lv = new Double(((Number)lv).doubleValue());
+                } else {
+                    return Boolean.FALSE;
+                }
+            } else if (lc == Float.class) {
+                if (rc == Integer.class) {
+                    rv = new Float(((Number)rv).floatValue());
+                } else if (rc == Long.class) {
+                    rv = new Float(((Number)rv).floatValue());
+                } else if (rc == Double.class) {
+                    lv = new Double(((Number)lv).doubleValue());
+                } else {
+                    return Boolean.FALSE;
+                }
+            } else if (lc == Double.class) {
+                if (rc == Integer.class) {
+                    rv = new Double(((Number)rv).doubleValue());
+                } else if (rc == Long.class) {
+                    rv = new Double(((Number)rv).doubleValue());
+                } else if (rc == Float.class) {
+                    rv = new Float(((Number)rv).doubleValue());
+                } else {
+                    return Boolean.FALSE;
+                }
+            } else {
+                return Boolean.FALSE;
+            }
+        }
+        return asBoolean(lv.compareTo(rv)) ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    protected abstract boolean asBoolean(int answer);
+
+    public boolean matches(MessageEvaluationContext message) throws FilterException {
+        Object object = evaluate(message);
+        return object != null && object == Boolean.TRUE;
+    }
+
+}

Propchange: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/ComparisonExpression.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/ConstantExpression.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/ConstantExpression.java?rev=780558&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/ConstantExpression.java (added)
+++ activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/ConstantExpression.java Mon Jun  1 04:05:34 2009
@@ -0,0 +1,163 @@
+/**
+ * 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.activemq.filter;
+
+import java.math.BigDecimal;
+
+
+/**
+ * Represents a constant expression
+ * 
+ * @version $Revision: 1.2 $
+ */
+public class ConstantExpression implements Expression {
+
+    static class BooleanConstantExpression extends ConstantExpression implements BooleanExpression {
+        public BooleanConstantExpression(Object value) {
+            super(value);
+        }
+
+        public boolean matches(MessageEvaluationContext message) throws FilterException {
+            Object object = evaluate(message);
+            return object != null && object == Boolean.TRUE;
+        }
+    }
+
+    public static final BooleanConstantExpression NULL = new BooleanConstantExpression(null);
+    public static final BooleanConstantExpression TRUE = new BooleanConstantExpression(Boolean.TRUE);
+    public static final BooleanConstantExpression FALSE = new BooleanConstantExpression(Boolean.FALSE);
+
+    private Object value;
+
+    public ConstantExpression(Object value) {
+        this.value = value;
+    }
+
+    public static ConstantExpression createFromDecimal(String text) {
+
+        // Strip off the 'l' or 'L' if needed.
+        if (text.endsWith("l") || text.endsWith("L")) {
+            text = text.substring(0, text.length() - 1);
+        }
+
+        Number value;
+        try {
+            value = new Long(text);
+        } catch (NumberFormatException e) {
+            // The number may be too big to fit in a long.
+            value = new BigDecimal(text);
+        }
+
+        long l = value.longValue();
+        if (Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE) {
+            value = Integer.valueOf(value.intValue());
+        }
+        return new ConstantExpression(value);
+    }
+
+    public static ConstantExpression createFromHex(String text) {
+        Number value = Long.valueOf(Long.parseLong(text.substring(2), 16));
+        long l = value.longValue();
+        if (Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE) {
+            value = Integer.valueOf(value.intValue());
+        }
+        return new ConstantExpression(value);
+    }
+
+    public static ConstantExpression createFromOctal(String text) {
+        Number value = Long.valueOf(Long.parseLong(text, 8));
+        long l = value.longValue();
+        if (Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE) {
+            value = Integer.valueOf(value.intValue());
+        }
+        return new ConstantExpression(value);
+    }
+
+    public static ConstantExpression createFloat(String text) {
+        Number value = new Double(text);
+        return new ConstantExpression(value);
+    }
+
+    public Object evaluate(MessageEvaluationContext message) throws FilterException {
+        return value;
+    }
+
+    public Object getValue() {
+        return value;
+    }
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString() {
+        if (value == null) {
+            return "NULL";
+        }
+        if (value instanceof Boolean) {
+            return ((Boolean)value).booleanValue() ? "TRUE" : "FALSE";
+        }
+        if (value instanceof String) {
+            return encodeString((String)value);
+        }
+        return value.toString();
+    }
+
+    /**
+     * TODO: more efficient hashCode()
+     * 
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode() {
+        return toString().hashCode();
+    }
+
+    /**
+     * TODO: more efficient hashCode()
+     * 
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals(Object o) {
+
+        if (o == null || !this.getClass().equals(o.getClass())) {
+            return false;
+        }
+        return toString().equals(o.toString());
+
+    }
+
+    /**
+     * Encodes the value of string so that it looks like it would look like when
+     * it was provided in a selector.
+     * 
+     * @param string
+     * @return
+     */
+    public static String encodeString(String s) {
+        StringBuffer b = new StringBuffer();
+        b.append('\'');
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            if (c == '\'') {
+                b.append(c);
+            }
+            b.append(c);
+        }
+        b.append('\'');
+        return b.toString();
+    }
+
+}

Propchange: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/ConstantExpression.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/Expression.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/Expression.java?rev=780558&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/Expression.java (added)
+++ activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/Expression.java Mon Jun  1 04:05:34 2009
@@ -0,0 +1,34 @@
+/**
+ * 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.activemq.filter;
+
+
+
+/**
+ * Represents an expression
+ * 
+ * @version $Revision: 1.2 $
+ */
+public interface Expression {
+
+    /**
+     * @return the value of this expression
+     */
+    Object evaluate(MessageEvaluationContext message) throws FilterException;
+    
+}

Propchange: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/Expression.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/FilterException.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/FilterException.java?rev=780558&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/FilterException.java (added)
+++ activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/FilterException.java Mon Jun  1 04:05:34 2009
@@ -0,0 +1,23 @@
+package org.apache.activemq.filter;
+
+public class FilterException extends Exception {
+
+    private static final long serialVersionUID = -6892363158919485507L;
+
+    public FilterException() {
+        super();
+    }
+
+    public FilterException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public FilterException(String message) {
+        super(message);
+    }
+
+    public FilterException(Throwable cause) {
+        super(cause);
+    }
+    
+}

Added: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/LogicExpression.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/LogicExpression.java?rev=780558&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/LogicExpression.java (added)
+++ activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/LogicExpression.java Mon Jun  1 04:05:34 2009
@@ -0,0 +1,88 @@
+/**
+ * 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.activemq.filter;
+
+
+/**
+ * A filter performing a comparison of two objects
+ * 
+ * @version $Revision: 1.2 $
+ */
+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(MessageEvaluationContext message) throws FilterException {
+
+                Boolean lv = (Boolean)left.evaluate(message);
+                // Can we do an OR shortcut??
+                if (lv != null && lv.booleanValue()) {
+                    return Boolean.TRUE;
+                }
+
+                Boolean rv = (Boolean)right.evaluate(message);
+                return rv == null ? null : rv;
+            }
+
+            public String getExpressionSymbol() {
+                return "OR";
+            }
+        };
+    }
+
+    public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue) {
+        return new LogicExpression(lvalue, rvalue) {
+
+            public Object evaluate(MessageEvaluationContext message) throws FilterException {
+
+                Boolean lv = (Boolean)left.evaluate(message);
+
+                // Can we do an AND shortcut??
+                if (lv == null) {
+                    return null;
+                }
+                if (!lv.booleanValue()) {
+                    return Boolean.FALSE;
+                }
+
+                Boolean rv = (Boolean)right.evaluate(message);
+                return rv == null ? null : rv;
+            }
+
+            public String getExpressionSymbol() {
+                return "AND";
+            }
+        };
+    }
+
+    public abstract Object evaluate(MessageEvaluationContext message) throws FilterException;
+
+    public boolean matches(MessageEvaluationContext message) throws FilterException {
+        Object object = evaluate(message);
+        return object != null && object == Boolean.TRUE;
+    }
+
+}

Propchange: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/LogicExpression.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/MessageEvaluationContext.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/MessageEvaluationContext.java?rev=780558&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/MessageEvaluationContext.java (added)
+++ activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/MessageEvaluationContext.java Mon Jun  1 04:05:34 2009
@@ -0,0 +1,123 @@
+/**
+ * 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.activemq.filter;
+
+
+
+/**
+ * MessageEvaluationContext is used to cache selection results. A message
+ * usually has multiple selectors applied against it. Some selector have a high
+ * cost of evaluating against the message. Those selectors may whish to cache
+ * evaluation results associated with the message in the
+ * MessageEvaluationContext.
+ * 
+ * @version $Revision: 1.4 $
+ */
+public interface MessageEvaluationContext {
+
+    /**
+     * This method is used by message filters which do content based routing (Like the XPath 
+     * based selectors).
+     * 
+     * @param <T>
+     * @param type
+     * @return
+     * @throws FilterException
+     */
+    <T> T getBodyAs(Class<T> type) throws FilterException;
+
+    /**
+     * Creates an expression which extracts the named property from a message.
+     * @param name
+     * @return
+     */
+    Expression getPropertyExpression(String name);
+
+    /**
+     * Stubbed in here to get stuff compiling but I think this can go away.  Used by the NoLocal filter.
+     * @return
+     */
+    @Deprecated
+    Object getLocalConnectionId();
+
+    /**
+     * @return the destination that the message is on
+     */
+    <T> T getDestination();
+
+    void setDestination(Object destination);
+
+//	protected MessageReference messageReference;
+//    protected boolean loaded;
+//    protected boolean dropped;
+//    protected Message message;
+//    protected ActiveMQDestination destination;
+//
+//    public MessageEvaluationContext() {
+//    }
+//
+//    public boolean isDropped() throws IOException {
+//        getMessage();
+//        return dropped;
+//    }
+//
+//    public Message getMessage() throws IOException {
+//        if (!dropped && !loaded) {
+//            loaded = true;
+//            messageReference.incrementReferenceCount();
+//            message = messageReference.getMessage();
+//            if (message == null) {
+//                messageReference.decrementReferenceCount();
+//                dropped = true;
+//                loaded = false;
+//            }
+//        }
+//        return message;
+//    }
+//
+//    public void setMessageReference(MessageReference messageReference) {
+//        if (this.messageReference != messageReference) {
+//            clearMessageCache();
+//        }
+//        this.messageReference = messageReference;
+//    }
+//
+//    public void clear() {
+//        clearMessageCache();
+//        destination = null;
+//    }
+//
+//    public ActiveMQDestination getDestination() {
+//        return destination;
+//    }
+//
+//    public void setDestination(ActiveMQDestination destination) {
+//        this.destination = destination;
+//    }
+//
+//    /**
+//     * A strategy hook to allow per-message caches to be cleared
+//     */
+//    protected void clearMessageCache() {
+//        if (loaded) {
+//            messageReference.decrementReferenceCount();
+//        }
+//        message = null;
+//        dropped = false;
+//        loaded = false;
+//    }
+}

Propchange: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/MessageEvaluationContext.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/PropertyExpression.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/PropertyExpression.java?rev=780558&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/PropertyExpression.java (added)
+++ activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/PropertyExpression.java Mon Jun  1 04:05:34 2009
@@ -0,0 +1,71 @@
+/**
+ * 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.activemq.filter;
+
+
+/**
+ * Represents a property expression
+ * 
+ * @version $Revision: 1.5 $
+ */
+public class PropertyExpression implements Expression {
+
+    private final String name;
+    private Expression expression;
+
+    public PropertyExpression(String name) {
+        this.name = name;
+    }
+
+    public Object evaluate(MessageEvaluationContext message) throws FilterException {
+        if (expression == null) {
+            expression = message.getPropertyExpression(name);
+        }
+        return expression.evaluate(message);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString() {
+        return name;
+    }
+
+    /**
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode() {
+        return name.hashCode();
+    }
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals(Object o) {
+        if (o == null || !this.getClass().equals(o.getClass())) {
+            return false;
+        }
+        return name.equals(((PropertyExpression)o).name);
+
+    }
+
+}

Propchange: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/PropertyExpression.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/UnaryExpression.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/UnaryExpression.java?rev=780558&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/UnaryExpression.java (added)
+++ activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/UnaryExpression.java Mon Jun  1 04:05:34 2009
@@ -0,0 +1,256 @@
+/**
+ * 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.activemq.filter;
+
+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
+ * 
+ * @version $Revision: 1.3 $
+ */
+public abstract class UnaryExpression implements Expression {
+
+    private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE);
+    protected Expression right;
+
+    public UnaryExpression(Expression left) {
+        this.right = left;
+    }
+
+    public static Expression createNegate(Expression left) {
+        return new UnaryExpression(left) {
+            public Object evaluate(MessageEvaluationContext message) throws FilterException {
+                Object rvalue = right.evaluate(message);
+                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<Object> inList = t;
+
+        return new BooleanUnaryExpression(right) {
+            public Object evaluate(MessageEvaluationContext message) throws FilterException {
+
+                Object rvalue = right.evaluate(message);
+                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<Object> 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) {
+            super(left);
+        }
+
+        public boolean matches(MessageEvaluationContext message) throws FilterException {
+            Object object = evaluate(message);
+            return object != null && object == Boolean.TRUE;
+        }
+    };
+
+    public static BooleanExpression createNOT(BooleanExpression left) {
+        return new BooleanUnaryExpression(left) {
+            public Object evaluate(MessageEvaluationContext message) throws FilterException {
+                Boolean lvalue = (Boolean)right.evaluate(message);
+                if (lvalue == null) {
+                    return null;
+                }
+                return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE;
+            }
+
+            public String getExpressionSymbol() {
+                return "NOT";
+            }
+        };
+    }
+
+    public static BooleanExpression createXPath(final String xpath) {
+        return new XPathExpression(xpath);
+    }
+
+    public static BooleanExpression createXQuery(final String xpath) {
+        return new XQueryExpression(xpath);
+    }
+
+    public static BooleanExpression createBooleanCast(Expression left) {
+        return new BooleanUnaryExpression(left) {
+            public Object evaluate(MessageEvaluationContext message) throws FilterException {
+                Object rvalue = right.evaluate(message);
+                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;
+    }
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString() {
+        return "(" + getExpressionSymbol() + " " + right.toString() + ")";
+    }
+
+    /**
+     * TODO: more efficient hashCode()
+     * 
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode() {
+        return toString().hashCode();
+    }
+
+    /**
+     * TODO: more efficient hashCode()
+     * 
+     * @see java.lang.Object#equals(java.lang.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();
+
+}

Propchange: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/UnaryExpression.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/XPathExpression.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/XPathExpression.java?rev=780558&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/XPathExpression.java (added)
+++ activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/XPathExpression.java Mon Jun  1 04:05:34 2009
@@ -0,0 +1,109 @@
+/**
+ * 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.activemq.filter;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * Used to evaluate an XPath Expression in a JMS selector.
+ */
+public final class XPathExpression implements BooleanExpression {
+
+    private static final Log LOG = LogFactory.getLog(XPathExpression.class);
+    private static final String EVALUATOR_SYSTEM_PROPERTY = "org.apache.activemq.XPathEvaluatorClassName";
+    private static final String DEFAULT_EVALUATOR_CLASS_NAME = XalanXPathEvaluator.class.getName();
+
+    private static final Constructor EVALUATOR_CONSTRUCTOR;
+
+    static {
+        String cn = System.getProperty(EVALUATOR_SYSTEM_PROPERTY, DEFAULT_EVALUATOR_CLASS_NAME);
+        Constructor m = null;
+        try {
+            try {
+                m = getXPathEvaluatorConstructor(cn);
+            } catch (Throwable e) {
+                LOG.warn("Invalid " + XPathEvaluator.class.getName() + " implementation: " + cn + ", reason: " + e, e);
+                cn = DEFAULT_EVALUATOR_CLASS_NAME;
+                try {
+                    m = getXPathEvaluatorConstructor(cn);
+                } catch (Throwable e2) {
+                    LOG.error("Default XPath evaluator could not be loaded", e);
+                }
+            }
+        } finally {
+            EVALUATOR_CONSTRUCTOR = m;
+        }
+    }
+
+    private final String xpath;
+    private final XPathEvaluator evaluator;
+
+    public static interface XPathEvaluator {
+        boolean evaluate(MessageEvaluationContext message) throws FilterException;
+    }
+
+    XPathExpression(String xpath) {
+        this.xpath = xpath;
+        this.evaluator = createEvaluator(xpath);
+    }
+
+    private static Constructor getXPathEvaluatorConstructor(String cn) throws ClassNotFoundException, SecurityException, NoSuchMethodException {
+        Class c = XPathExpression.class.getClassLoader().loadClass(cn);
+        if (!XPathEvaluator.class.isAssignableFrom(c)) {
+            throw new ClassCastException("" + c + " is not an instance of " + XPathEvaluator.class);
+        }
+        return c.getConstructor(new Class[] {String.class});
+    }
+
+    private XPathEvaluator createEvaluator(String xpath2) {
+        try {
+            return (XPathEvaluator)EVALUATOR_CONSTRUCTOR.newInstance(new Object[] {xpath});
+        } catch (InvocationTargetException e) {
+            Throwable cause = e.getCause();
+            if (cause instanceof RuntimeException) {
+                throw (RuntimeException)cause;
+            }
+            throw new RuntimeException("Invalid XPath Expression: " + xpath + " reason: " + e.getMessage(), e);
+        } catch (Throwable e) {
+            throw new RuntimeException("Invalid XPath Expression: " + xpath + " reason: " + e.getMessage(), e);
+        }
+    }
+
+    public Object evaluate(MessageEvaluationContext message) throws FilterException {
+        return evaluator.evaluate(message) ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    public String toString() {
+        return "XPATH " + ConstantExpression.encodeString(xpath);
+    }
+
+    /**
+     * @param message
+     * @return true if the expression evaluates to Boolean.TRUE.
+     * @throws FilterException
+     */
+    public boolean matches(MessageEvaluationContext message) throws FilterException {
+        Object object = evaluate(message);
+        return object != null && object == Boolean.TRUE;
+    }
+
+}

Propchange: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/XPathExpression.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/XQueryExpression.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/XQueryExpression.java?rev=780558&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/XQueryExpression.java (added)
+++ activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/XQueryExpression.java Mon Jun  1 04:05:34 2009
@@ -0,0 +1,49 @@
+/**
+ * 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.activemq.filter;
+
+
+/**
+ * Used to evaluate an XQuery Expression in a JMS selector.
+ */
+public final class XQueryExpression implements BooleanExpression {
+    private final String xpath;
+
+    XQueryExpression(String xpath) {
+        super();
+        this.xpath = xpath;
+    }
+
+    public Object evaluate(MessageEvaluationContext message) throws FilterException {
+        return Boolean.FALSE;
+    }
+
+    public String toString() {
+        return "XQUERY " + ConstantExpression.encodeString(xpath);
+    }
+
+    /**
+     * @param message
+     * @return true if the expression evaluates to Boolean.TRUE.
+     * @throws FilterException
+     */
+    public boolean matches(MessageEvaluationContext message) throws FilterException {
+        Object object = evaluate(message);
+        return object != null && object == Boolean.TRUE;
+    }
+
+}

Propchange: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/XQueryExpression.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/XalanXPathEvaluator.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/XalanXPathEvaluator.java?rev=780558&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/XalanXPathEvaluator.java (added)
+++ activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/XalanXPathEvaluator.java Mon Jun  1 04:05:34 2009
@@ -0,0 +1,106 @@
+/**
+ * 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.activemq.filter;
+
+import java.io.StringReader;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.activemq.protobuf.Buffer;
+import org.apache.activemq.protobuf.BufferInputStream;
+import org.apache.xpath.CachedXPathAPI;
+import org.apache.xpath.objects.XObject;
+import org.w3c.dom.Document;
+import org.w3c.dom.traversal.NodeIterator;
+import org.xml.sax.InputSource;
+
+
+public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator {
+
+    private final String xpath;
+
+    public XalanXPathEvaluator(String xpath) {
+        this.xpath = xpath;
+    }
+
+    public boolean evaluate(MessageEvaluationContext m) throws FilterException {
+        String stringBody = m.getBodyAs(String.class);
+        if (stringBody!=null) {
+            return evaluate(stringBody);
+        } 
+        
+        Buffer bufferBody = m.getBodyAs(Buffer.class);
+        if (bufferBody!=null) {
+            return evaluate(bufferBody);
+        } 
+        return false;
+    }
+
+    private boolean evaluate(Buffer data) {
+        try {
+
+            InputSource inputSource = new InputSource(new BufferInputStream(data));
+
+            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            factory.setNamespaceAware(true);
+            DocumentBuilder dbuilder = factory.newDocumentBuilder();
+            Document doc = dbuilder.parse(inputSource);
+            
+            CachedXPathAPI cachedXPathAPI = new CachedXPathAPI();
+            XObject result = cachedXPathAPI.eval(doc, xpath);
+            if (result.bool())
+            	return true;
+            else {
+            	NodeIterator iterator = cachedXPathAPI.selectNodeIterator(doc, xpath);
+            	return (iterator.nextNode() != null);
+            }  
+
+        } catch (Throwable e) {
+            return false;
+        }
+    }
+
+    private boolean evaluate(String text) {
+        try {
+            InputSource inputSource = new InputSource(new StringReader(text));
+
+            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            factory.setNamespaceAware(true);
+            DocumentBuilder dbuilder = factory.newDocumentBuilder();
+            Document doc = dbuilder.parse(inputSource);
+
+            //An XPath expression could return a true or false value instead of a node.
+            //eval() is a better way to determine the boolean value of the exp.
+            //For compliance with legacy behavior where selecting an empty node returns true,
+            //selectNodeIterator is attempted in case of a failure.
+            
+            CachedXPathAPI cachedXPathAPI = new CachedXPathAPI();
+            XObject result = cachedXPathAPI.eval(doc, xpath);
+            if (result.bool())
+            	return true;
+            else {
+            	NodeIterator iterator = cachedXPathAPI.selectNodeIterator(doc, xpath);
+            	return (iterator.nextNode() != null);
+            }    	
+            
+        } catch (Throwable e) {
+            return false;
+        }
+    }
+}

Propchange: activemq/sandbox/activemq-flow/activemq-selector/src/main/java/org/apache/activemq/filter/XalanXPathEvaluator.java
------------------------------------------------------------------------------
    svn:executable = *