You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by an...@apache.org on 2010/03/09 15:16:09 UTC

svn commit: r920884 [2/4] - in /cayenne/sandbox/cayenne-gwt/src: main/java/org/apache/cayenne/gwt/ main/java/org/apache/cayenne/gwt/client/ main/java/org/apache/cayenne/gwt/server/ main/java/org/apache/cayenne/query/ main/resources/org/apache/cayenne/ ...

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/ExpressionFactory.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/ExpressionFactory.java?rev=920884&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/ExpressionFactory.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/ExpressionFactory.java Tue Mar  9 14:16:07 2010
@@ -0,0 +1,628 @@
+/*****************************************************************
+ *   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.cayenne.exp;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cayenne.Persistent;
+import org.apache.cayenne.exp.parser.ASTAnd;
+import org.apache.cayenne.exp.parser.ASTBetween;
+import org.apache.cayenne.exp.parser.ASTDbPath;
+import org.apache.cayenne.exp.parser.ASTEqual;
+import org.apache.cayenne.exp.parser.ASTFalse;
+import org.apache.cayenne.exp.parser.ASTGreater;
+import org.apache.cayenne.exp.parser.ASTGreaterOrEqual;
+import org.apache.cayenne.exp.parser.ASTIn;
+import org.apache.cayenne.exp.parser.ASTLess;
+import org.apache.cayenne.exp.parser.ASTLessOrEqual;
+import org.apache.cayenne.exp.parser.ASTLike;
+import org.apache.cayenne.exp.parser.ASTLikeIgnoreCase;
+import org.apache.cayenne.exp.parser.ASTList;
+import org.apache.cayenne.exp.parser.ASTNotBetween;
+import org.apache.cayenne.exp.parser.ASTNotEqual;
+import org.apache.cayenne.exp.parser.ASTNotIn;
+import org.apache.cayenne.exp.parser.ASTNotLike;
+import org.apache.cayenne.exp.parser.ASTNotLikeIgnoreCase;
+import org.apache.cayenne.exp.parser.ASTObjPath;
+import org.apache.cayenne.exp.parser.ASTOr;
+import org.apache.cayenne.exp.parser.ASTPath;
+import org.apache.cayenne.exp.parser.ASTTrue;
+
+/**
+ * Helper class to build expressions. Alternatively expressions can be built using
+ * {@link org.apache.cayenne.exp.Expression#fromString(String)} method.
+ * 
+ */
+public class ExpressionFactory {
+
+    /**
+     * A "split" character, "|", that is understood by some of the ExpressionFactory
+     * methods that require splitting joins in the middle of the path.
+     * 
+     * @since 3.0
+     */
+    public static final char SPLIT_SEPARATOR = '|';
+
+    private static volatile int autoAliasId;
+
+    /**
+     * Creates a new expression for the type requested. If type is unknown,
+     * ExpressionException is thrown.
+     */
+    public static Expression expressionOfType(int type) {
+        if (type == Expression.AND) {
+        	return new ASTAnd();
+        }
+        if (type == Expression.OR) {
+        	return new ASTOr();
+        }
+
+        throw new ExpressionException("Bad expression type: " + type);
+    }
+
+    /**
+     * Applies a few default rules for adding operands to expressions. In particular wraps
+     * all lists into LIST expressions. Applied only in path expressions.
+     */
+    protected static Object wrapPathOperand(Object op) {
+        if (op instanceof Collection) {
+            return new ASTList((Collection<?>) op);
+        }
+        else if (op instanceof Object[]) {
+            return new ASTList((Object[]) op);
+        }
+        else {
+            return op;
+        }
+    }
+
+    /**
+     * Creates an expression that matches any of the key-values pairs in <code>map</code>.
+     * <p>
+     * For each pair <code>pairType</code> operator is used to build a binary
+     * expression. Key is considered to be a DB_PATH expression. OR is used to join pair
+     * binary expressions.
+     */
+    public static Expression matchAnyDbExp(Map<String, ?> map, int pairType) {
+        List<Expression> pairs = new ArrayList<Expression>(map.size());
+
+        for (Map.Entry<String, ?> entry : map.entrySet()) {
+            Expression exp = expressionOfType(pairType);
+            exp.setOperand(0, new ASTDbPath(entry.getKey()));
+            exp.setOperand(1, wrapPathOperand(entry.getValue()));
+            pairs.add(exp);
+        }
+
+        return joinExp(Expression.OR, pairs);
+    }
+
+    /**
+     * Creates an expression that matches all key-values pairs in <code>map</code>.
+     * <p>
+     * For each pair <code>pairType</code> operator is used to build a binary
+     * expression. Key is considered to be a DB_PATH expression. AND is used to join pair
+     * binary expressions.
+     */
+    public static Expression matchAllDbExp(Map<String, ?> map, int pairType) {
+        List<Expression> pairs = new ArrayList<Expression>(map.size());
+
+        for (Map.Entry<String, ?> entry : map.entrySet()) {
+            Expression exp = expressionOfType(pairType);
+            exp.setOperand(0, new ASTDbPath(entry.getKey()));
+            exp.setOperand(1, wrapPathOperand(entry.getValue()));
+            pairs.add(exp);
+        }
+
+        return joinExp(Expression.AND, pairs);
+    }
+
+    /**
+     * Creates an expression that matches any of the key-values pairs in the
+     * <code>map</code>.
+     * <p>
+     * For each pair <code>pairType</code> operator is used to build a binary
+     * expression. Key is considered to be a OBJ_PATH expression. OR is used to join pair
+     * binary expressions.
+     */
+    public static Expression matchAnyExp(Map<String, ?> map, int pairType) {
+        List<Expression> pairs = new ArrayList<Expression>(map.size());
+
+        for (Map.Entry<String, ?> entry : map.entrySet()) {
+
+            Expression exp = expressionOfType(pairType);
+            exp.setOperand(0, new ASTObjPath(entry.getKey()));
+            exp.setOperand(1, wrapPathOperand(entry.getValue()));
+            pairs.add(exp);
+        }
+
+        return joinExp(Expression.OR, pairs);
+    }
+
+    /**
+     * Creates an expression to match a collection of values against a single path
+     * expression.
+     * <h3>Splits</h3>
+     * <p>
+     * Note that "path" argument here can use a split character (a pipe symbol - '|')
+     * instead of dot to indicate that relationship following a path should be split into
+     * a separate set of joins. There can only be one split at most. Split must always
+     * precede a relationship. E.g. "|exhibits.paintings", "exhibits|paintings", etc.
+     * 
+     * @param path
+     * @param values
+     * @since 3.0
+     */
+    @SuppressWarnings("unchecked")
+    public static Expression matchAllExp(String path, Collection values) {
+
+        if (values == null) {
+            throw new NullPointerException("Null values collection");
+        }
+
+        if (values.size() == 0) {
+            return new ASTTrue();
+        }
+
+        return matchAllExp(path, values.toArray());
+    }
+
+    /**
+     * @since 3.0
+     */
+    public static Expression matchAllExp(String path, Object... values) {
+
+        if (values == null) {
+            throw new NullPointerException("Null values collection");
+        }
+
+        if (values.length == 0) {
+            return new ASTTrue();
+        }
+
+        int split = path.indexOf(SPLIT_SEPARATOR);
+
+        List<Expression> matches = new ArrayList<Expression>(values.length);
+
+        if (split >= 0 && split < path.length() - 1) {
+
+            int splitEnd = path.indexOf(".", split + 1);
+
+            String beforeSplit = split > 0 ? path.substring(0, split) + "." : "";
+            String afterSplit = splitEnd > 0 ? "." + path.substring(splitEnd + 1) : "";
+            String aliasBase = "split" + autoAliasId++ + "_";
+            String splitChunk = splitEnd > 0 ? path.substring(split + 1, splitEnd) : path
+                    .substring(split + 1);
+
+            // fix the path - replace split with dot if it's in the middle, or strip it if
+            // it's in the beginning
+            path = split == 0 ? path.substring(1) : path.replace(SPLIT_SEPARATOR, '.');
+
+            int i = 0;
+            for (Object value : values) {
+
+                String alias = aliasBase + i;
+                String aliasedPath = beforeSplit + alias + afterSplit;
+                i++;
+
+                ASTPath pathExp = new ASTObjPath(aliasedPath);
+                pathExp.setPathAliases(Collections.singletonMap(alias, splitChunk));
+                matches.add(new ASTEqual(pathExp, value));
+            }
+        }
+        else {
+            for (Object value : values) {
+                matches.add(new ASTEqual(new ASTObjPath(path), value));
+            }
+        }
+
+        return joinExp(Expression.AND, matches);
+    }
+
+    /**
+     * Creates an expression that matches all key-values pairs in <code>map</code>.
+     * <p>
+     * For each pair <code>pairType</code> operator is used to build a binary
+     * expression. Key is considered to be a OBJ_PATH expression. AND is used to join pair
+     * binary expressions.
+     */
+    public static Expression matchAllExp(Map<String, ?> map, int pairType) {
+        List<Expression> pairs = new ArrayList<Expression>(map.size());
+
+        for (Map.Entry<String, ?> entry : map.entrySet()) {
+
+            Expression exp = expressionOfType(pairType);
+            exp.setOperand(0, new ASTObjPath(entry.getKey()));
+            exp.setOperand(1, wrapPathOperand(entry.getValue()));
+            pairs.add(exp);
+        }
+
+        return joinExp(Expression.AND, pairs);
+    }
+
+    /**
+     * A convenience method to create an DB_PATH "equal to" expression.
+     */
+    public static Expression matchDbExp(String pathSpec, Object value) {
+        return new ASTEqual(new ASTDbPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience method to create an DB_PATH "not equal to" expression.
+     */
+    public static Expression noMatchDbExp(String pathSpec, Object value) {
+        return new ASTNotEqual(new ASTDbPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience method to create an OBJ_PATH "equal to" expression.
+     */
+    public static Expression matchExp(String pathSpec, Object value) {
+        return new ASTEqual(new ASTObjPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience method to create an OBJ_PATH "not equal to" expression.
+     */
+    public static Expression noMatchExp(String pathSpec, Object value) {
+        return new ASTNotEqual(new ASTObjPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience method to create an OBJ_PATH "less than" expression.
+     */
+    public static Expression lessExp(String pathSpec, Object value) {
+        return new ASTLess(new ASTObjPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience method to create an DB_PATH "less than" expression.
+     * 
+     * @since 3.0
+     */
+    public static Expression lessDbExp(String pathSpec, Object value) {
+        return new ASTLess(new ASTDbPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience method to create an OBJ_PATH "less than or equal to" expression.
+     */
+    public static Expression lessOrEqualExp(String pathSpec, Object value) {
+        return new ASTLessOrEqual(new ASTObjPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience method to create an DB_PATH "less than or equal to" expression.
+     * 
+     * @since 3.0
+     */
+    public static Expression lessOrEqualDbExp(String pathSpec, Object value) {
+        return new ASTLessOrEqual(new ASTDbPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience method to create an OBJ_PATH "greater than" expression.
+     */
+    public static Expression greaterExp(String pathSpec, Object value) {
+        return new ASTGreater(new ASTObjPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience method to create an DB_PATH "greater than" expression.
+     * 
+     * @since 3.0
+     */
+    public static Expression greaterDbExp(String pathSpec, Object value) {
+        return new ASTGreater(new ASTDbPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience method to create an OBJ_PATH "greater than or equal to" expression.
+     */
+    public static Expression greaterOrEqualExp(String pathSpec, Object value) {
+        return new ASTGreaterOrEqual(new ASTObjPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience method to create an DB_PATH "greater than or equal to" expression.
+     * 
+     * @since 3.0
+     */
+    public static Expression greaterOrEqualDbExp(String pathSpec, Object value) {
+        return new ASTGreaterOrEqual(new ASTDbPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience shortcut for building IN expression. Return ASTFalse for empty
+     * collection.
+     */
+    public static Expression inExp(String pathSpec, Object... values) {
+        if (values.length == 0) {
+            return new ASTFalse();
+        }
+        return new ASTIn(new ASTObjPath(pathSpec), new ASTList(values));
+    }
+
+    /**
+     * A convenience shortcut for building IN DB expression. Return ASTFalse for empty
+     * collection.
+     */
+    public static Expression inDbExp(String pathSpec, Object... values) {
+        if (values.length == 0) {
+            return new ASTFalse();
+        }
+        return new ASTIn(new ASTDbPath(pathSpec), new ASTList(values));
+    }
+
+    /**
+     * A convenience shortcut for building IN expression. Return ASTFalse for empty
+     * collection.
+     */
+    public static Expression inExp(String pathSpec, Collection<?> values) {
+        if (values.isEmpty()) {
+            return new ASTFalse();
+        }
+        return new ASTIn(new ASTObjPath(pathSpec), new ASTList(values));
+    }
+
+    /**
+     * A convenience shortcut for building IN DB expression. Return ASTFalse for empty
+     * collection.
+     */
+    public static Expression inDbExp(String pathSpec, Collection<?> values) {
+        if (values.isEmpty()) {
+            return new ASTFalse();
+        }
+        return new ASTIn(new ASTDbPath(pathSpec), new ASTList(values));
+    }
+
+    /**
+     * A convenience shortcut for building NOT_IN expression. Return ASTTrue for empty
+     * collection.
+     */
+    public static Expression notInExp(String pathSpec, Collection<?> values) {
+        if (values.isEmpty()) {
+            return new ASTTrue();
+        }
+        return new ASTNotIn(new ASTObjPath(pathSpec), new ASTList(values));
+    }
+
+    /**
+     * A convenience shortcut for building NOT_IN expression. Return ASTTrue for empty
+     * collection.
+     * 
+     * @since 3.0
+     */
+    public static Expression notInDbExp(String pathSpec, Collection<?> values) {
+        if (values.isEmpty()) {
+            return new ASTTrue();
+        }
+        return new ASTNotIn(new ASTDbPath(pathSpec), new ASTList(values));
+    }
+
+    /**
+     * A convenience shortcut for building NOT_IN expression. Return ASTTrue for empty
+     * collection.
+     * 
+     * @since 1.0.6
+     */
+    public static Expression notInExp(String pathSpec, Object... values) {
+        if (values.length == 0) {
+            return new ASTTrue();
+        }
+        return new ASTNotIn(new ASTObjPath(pathSpec), new ASTList(values));
+    }
+
+    /**
+     * A convenience shortcut for building NOT_IN expression. Return ASTTrue for empty
+     * collection.
+     * 
+     * @since 3.0
+     */
+    public static Expression notInDbExp(String pathSpec, Object... values) {
+        if (values.length == 0) {
+            return new ASTTrue();
+        }
+        return new ASTNotIn(new ASTDbPath(pathSpec), new ASTList(values));
+    }
+
+    /**
+     * A convenience shortcut for building BETWEEN expressions.
+     */
+    public static Expression betweenExp(String pathSpec, Object value1, Object value2) {
+        return new ASTBetween(new ASTObjPath(pathSpec), value1, value2);
+    }
+
+    /**
+     * A convenience shortcut for building BETWEEN expressions.
+     * 
+     * @since 3.0
+     */
+    public static Expression betweenDbExp(String pathSpec, Object value1, Object value2) {
+        return new ASTBetween(new ASTDbPath(pathSpec), value1, value2);
+    }
+
+    /**
+     * A convenience shortcut for building NOT_BETWEEN expressions.
+     */
+    public static Expression notBetweenExp(String pathSpec, Object value1, Object value2) {
+        return new ASTNotBetween(new ASTObjPath(pathSpec), value1, value2);
+    }
+
+    /**
+     * A convenience shortcut for building NOT_BETWEEN expressions.
+     * 
+     * @since 3.0
+     */
+    public static Expression notBetweenDbExp(String pathSpec, Object value1, Object value2) {
+        return new ASTNotBetween(new ASTDbPath(pathSpec), value1, value2);
+    }
+
+    /**
+     * A convenience shortcut for building LIKE expression.
+     */
+    public static Expression likeExp(String pathSpec, Object value) {
+        return new ASTLike(new ASTObjPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience shortcut for building LIKE DB_PATH expression.
+     * 
+     * @since 3.0
+     */
+    public static Expression likeDbExp(String pathSpec, Object value) {
+        return new ASTLike(new ASTDbPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience shortcut for building NOT_LIKE expression.
+     */
+    public static Expression notLikeExp(String pathSpec, Object value) {
+        return new ASTNotLike(new ASTObjPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience shortcut for building NOT_LIKE expression.
+     * 
+     * @since 3.0
+     */
+    public static Expression notLikeDbExp(String pathSpec, Object value) {
+        return new ASTNotLike(new ASTDbPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience shortcut for building LIKE_IGNORE_CASE expression.
+     */
+    public static Expression likeIgnoreCaseExp(String pathSpec, Object value) {
+        return new ASTLikeIgnoreCase(new ASTObjPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience shortcut for building LIKE_IGNORE_CASE expression.
+     * 
+     * @since 3.0
+     */
+    public static Expression likeIgnoreCaseDbExp(String pathSpec, Object value) {
+        return new ASTLikeIgnoreCase(new ASTDbPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience shortcut for building NOT_LIKE_IGNORE_CASE expression.
+     */
+    public static Expression notLikeIgnoreCaseExp(String pathSpec, Object value) {
+        return new ASTNotLikeIgnoreCase(new ASTObjPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience shortcut for building NOT_LIKE_IGNORE_CASE expression.
+     * 
+     * @since 3.0
+     */
+    public static Expression notLikeIgnoreCaseDbExp(String pathSpec, Object value) {
+        return new ASTNotLikeIgnoreCase(new ASTDbPath(pathSpec), value);
+    }
+
+    /**
+     * A convenience shortcut for boolean true expression.
+     * 
+     * @since 3.0
+     */
+    public static Expression expTrue() {
+        return new ASTTrue();
+    }
+
+    /**
+     * A convenience shortcut for boolean false expression.
+     * 
+     * @since 3.0
+     */
+    public static Expression expFalse() {
+        return new ASTFalse();
+    }
+
+    /**
+     * Joins all <code>expressions</code> in a single expression. <code>type</code> is
+     * used as an expression type for expressions joining each one of the items on the
+     * list. <code>type</code> must be binary expression type.
+     * <p>
+     * For example, if type is Expression.AND, resulting expression would match all
+     * expressions in the list. If type is Expression.OR, resulting expression would match
+     * any of the expressions.
+     * </p>
+     */
+    public static Expression joinExp(int type, List<Expression> expressions) {
+        int len = expressions.size();
+        if (len == 0)
+            return null;
+
+        Expression currentExp = expressions.get(0);
+        if (len == 1) {
+            return currentExp;
+        }
+
+        Expression exp = expressionOfType(type);
+        for (int i = 0; i < len; i++) {
+            exp.setOperand(i, expressions.get(i));
+        }
+        return exp;
+    }
+    
+    /**
+     * Creates an expression that matches the primary key of object in
+     * <code>ObjectId</code>'s <code>IdSnapshot</code> for the argument
+     * <code>object</code>.
+     */
+    public static Expression matchExp(Persistent object) {
+        return matchAllDbExp(object.getObjectId().getIdSnapshot(), Expression.EQUAL_TO);
+    }
+
+    /**
+     * Creates an expression that matches any of the objects contained in the list
+     * <code>objects</code>
+     */
+    public static Expression matchAnyExp(List<? extends Persistent> objects) {
+        if (objects == null || objects.size() == 0) {
+            return expFalse();
+        }
+        
+        return matchAnyExp(objects.toArray(new Persistent[objects.size()]));
+    } 
+    
+    /**
+     * Creates an expression that matches any of the objects contained in the
+     * <code>objects</code> array
+     */
+    public static Expression matchAnyExp(Persistent... objects) {
+        if (objects == null || objects.length == 0) {
+            return expFalse();
+        }
+        
+        List<Expression> pairs = new ArrayList<Expression>(objects.length);
+
+        for (Persistent object : objects) {
+            pairs.add(matchExp(object));
+        }
+
+        return joinExp(Expression.OR, pairs);
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/ExpressionParameter.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/ExpressionParameter.java?rev=920884&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/ExpressionParameter.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/ExpressionParameter.java Tue Mar  9 14:16:07 2010
@@ -0,0 +1,62 @@
+/*****************************************************************
+ *   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.cayenne.exp;
+
+import java.io.Serializable;
+
+import org.apache.cayenne.util.Util;
+
+/**
+ * Named parameter for paramterized expressions.
+ * 
+ */
+public class ExpressionParameter implements Serializable {
+	protected String name;
+
+    /**
+     * Constructor for ExpressionParam.
+     */
+    public ExpressionParameter(String name) {
+        this.name = name;
+    }
+    
+    /**
+     * Returns the name of the expression parameter.
+     */
+    public String getName() {
+        return name;
+    }
+    
+    @Override
+    public String toString() {
+    	return '$' + name;
+    }
+    
+    @Override
+    public boolean equals(Object o) {
+        if(!(o instanceof ExpressionParameter)) {
+            return false;
+        }
+        
+        ExpressionParameter parameter = (ExpressionParameter)o;
+        return Util.nullSafeEquals(name, parameter.name);
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/TraversalHandler.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/TraversalHandler.java?rev=920884&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/TraversalHandler.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/TraversalHandler.java Tue Mar  9 14:16:07 2010
@@ -0,0 +1,59 @@
+/*****************************************************************
+ *   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.cayenne.exp;
+
+/**
+ * Expression visitor interface. Defines callback methods invoked when 
+ * walking the expression using {@link Expression#traverse(TraversalHandler)}.
+ * 
+ */
+public interface TraversalHandler {
+
+    /** 
+     * Called during traversal after a child of expression
+     * has been visited. 
+     */
+    public void finishedChild(
+        Expression node,
+        int childIndex,
+        boolean hasMoreChildren);
+  
+    /** 
+     * Called during the traversal before an expression node children
+     * processing is started.
+     * 
+     * @since 1.1
+     */
+    public void startNode(Expression node, Expression parentNode);
+    
+    /** 
+     * Called during the traversal after an expression node children
+     * processing is finished.
+     * 
+     * @since 1.1
+     */
+    public void endNode(Expression node, Expression parentNode);
+    
+    /** 
+     * Called during the traversal when a leaf non-expression node 
+     * is encountered.
+     */
+    public void objectNode(Object leaf, Expression parentNode);
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTAdd.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTAdd.java?rev=920884&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTAdd.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTAdd.java Tue Mar  9 14:16:07 2010
@@ -0,0 +1,105 @@
+/*****************************************************************
+ *   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.cayenne.exp.parser;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.cayenne.exp.Expression;
+
+/**
+ * "Add" Expression.
+ * 
+ */
+public class ASTAdd extends SimpleNode {
+    ASTAdd(int id) {
+        super(id);
+    }
+
+    public ASTAdd() {
+        super(ExpressionParserTreeConstants.JJTADD);
+    }
+
+    public ASTAdd(Object[] nodes) {
+        super(ExpressionParserTreeConstants.JJTADD);
+        int len = nodes.length;
+        for (int i = 0; i < len; i++) {
+            jjtAddChild(wrapChild(nodes[i]), i);
+        }
+        
+        connectChildren();
+    }
+
+    public ASTAdd(Collection nodes) {
+        super(ExpressionParserTreeConstants.JJTADD);
+        int len = nodes.size();
+        Iterator it = nodes.iterator();
+        for (int i = 0; i < len; i++) {
+            jjtAddChild(wrapChild(it.next()), i);
+        }
+        
+        connectChildren();
+    }
+
+    @Override
+    protected Object evaluateNode(Object o) throws Exception {
+        int len = jjtGetNumChildren();
+        if (len == 0) {
+            return null;
+        }
+
+        Double result = null;
+        for (int i = 0; i < len; i++) {
+            Number val = (Number) evaluateChild(i, o);
+
+            if (val == null) {
+                return null;
+            }
+
+            result = (i == 0) ? val.doubleValue() : result + val.doubleValue();
+        }
+
+        return result;
+    }
+
+    /**
+     * Creates a copy of this expression node, without copying children.
+     */
+    @Override
+    public Expression shallowCopy() {
+        return new ASTAdd(id);
+    }
+
+    @Override
+    protected String getExpressionOperator(int index) {
+        return "+";
+    }
+
+    @Override
+    public int getType() {
+        return Expression.ADD;
+    }
+
+    @Override
+    public void jjtClose() {
+        super.jjtClose();
+        flattenTree();
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTAnd.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTAnd.java?rev=920884&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTAnd.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTAnd.java Tue Mar  9 14:16:07 2010
@@ -0,0 +1,105 @@
+/*****************************************************************
+ *   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.cayenne.exp.parser;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.util.ConversionUtil;
+
+/**
+ * "And" expression.
+ * 
+ * @since 1.1
+ */
+public class ASTAnd extends AggregateConditionNode {
+    /**
+     * Constructor used by expression parser. Do not invoke directly.
+     */
+    ASTAnd(int id) {
+        super(id);
+    }
+
+    public ASTAnd() {
+        super(ExpressionParserTreeConstants.JJTAND);
+    }
+
+    public ASTAnd(Object[] nodes) {
+        super(ExpressionParserTreeConstants.JJTAND);
+        int len = nodes.length;
+        for (int i = 0; i < len; i++) {
+            jjtAddChild((Node) nodes[i], i);
+        }
+        
+        connectChildren();
+    }
+
+    public ASTAnd(Collection<? extends Node> nodes) {
+        super(ExpressionParserTreeConstants.JJTAND);
+        int len = nodes.size();
+        Iterator<? extends Node> it = nodes.iterator();
+        for (int i = 0; i < len; i++) {
+            jjtAddChild(it.next(), i);
+        }
+        
+        connectChildren();
+    }
+
+    @Override
+    protected Object evaluateNode(Object o) throws Exception {
+        int len = jjtGetNumChildren();
+        if (len == 0) {
+            return Boolean.FALSE;
+        }
+
+        for (int i = 0; i < len; i++) {
+            if (!ConversionUtil.toBoolean(evaluateChild(i, o))) {
+                return Boolean.FALSE;
+            }
+        }
+
+        return Boolean.TRUE;
+    }
+
+    /**
+     * Creates a copy of this expression node, without copying children.
+     */
+    @Override
+    public Expression shallowCopy() {
+        return new ASTAnd(id);
+    }
+
+    @Override
+    public int getType() {
+        return Expression.AND;
+    }
+
+    @Override
+    public void jjtClose() {
+        super.jjtClose();
+        flattenTree();
+    }
+
+    @Override
+    protected String getExpressionOperator(int index) {
+        return "and";
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTBetween.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTBetween.java?rev=920884&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTBetween.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTBetween.java Tue Mar  9 14:16:07 2010
@@ -0,0 +1,93 @@
+/*****************************************************************
+ *   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.cayenne.exp.parser;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.util.ConversionUtil;
+
+/**
+ * "Between" expression.
+ * 
+ * @since 1.1
+ */
+public class ASTBetween extends ConditionNode {
+
+    ASTBetween(int id) {
+        super(id);
+    }
+
+    public ASTBetween() {
+        super(ExpressionParserTreeConstants.JJTBETWEEN);
+    }
+
+    public ASTBetween(ASTPath path, Object value1, Object value2) {
+        super(ExpressionParserTreeConstants.JJTBETWEEN);
+        jjtAddChild(path, 0);
+        jjtAddChild(new ASTScalar(value1), 1);
+        jjtAddChild(new ASTScalar(value2), 2);
+        
+        connectChildren();
+    }
+
+    @Override
+    protected Object evaluateNode(Object o) throws Exception {
+        int len = jjtGetNumChildren();
+        if (len != 3) {
+            return Boolean.FALSE;
+        }
+
+        Comparable c1 = ConversionUtil.toComparable(evaluateChild(0, o));
+
+        if (c1 == null) {
+            return Boolean.FALSE;
+        }
+
+        Comparable c2 = ConversionUtil.toComparable(evaluateChild(1, o));
+        if (c2 == null) {
+            return Boolean.FALSE;
+        }
+
+        Comparable c3 = ConversionUtil.toComparable(evaluateChild(2, o));
+        if (c3 == null) {
+            return Boolean.FALSE;
+        }
+
+        return c1.compareTo(c2) >= 0
+            && c1.compareTo(c3) <= 0 ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Creates a copy of this expression node, without copying children.
+     */
+    @Override
+    public Expression shallowCopy() {
+        return new ASTBetween(id);
+    }
+
+    @Override
+    protected String getExpressionOperator(int index) {
+        return (index == 2) ? "and" : "between";
+    }
+
+    @Override
+    public int getType() {
+        return Expression.BETWEEN;
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTDbPath.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTDbPath.java?rev=920884&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTDbPath.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTDbPath.java Tue Mar  9 14:16:07 2010
@@ -0,0 +1,64 @@
+/*****************************************************************
+ *   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.cayenne.exp.parser;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionException;
+
+/**
+ * Path expression traversing DB relationships and attributes.
+ * 
+ * @since 1.1
+ */
+public class ASTDbPath extends ASTPath {
+
+    ASTDbPath(int id) {
+        super(id);
+    }
+
+    public ASTDbPath() {
+        super(ExpressionParserTreeConstants.JJTDBPATH);
+    }
+
+    public ASTDbPath(Object value) {
+        super(ExpressionParserTreeConstants.JJTDBPATH);
+        setPath(value);
+    }
+
+    @Override
+    protected Object evaluateNode(Object o) throws Exception {
+        throw new ExpressionException("Cannot evaluate db path on client");
+    }
+
+    /**
+     * Creates a copy of this expression node, without copying children.
+     */
+    @Override
+    public Expression shallowCopy() {
+        ASTDbPath copy = new ASTDbPath(id);
+        copy.path = path;
+        return copy;
+    }
+
+    @Override
+    public int getType() {
+        return Expression.DB_PATH;
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTDivide.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTDivide.java?rev=920884&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTDivide.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTDivide.java Tue Mar  9 14:16:07 2010
@@ -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.cayenne.exp.parser;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.cayenne.exp.Expression;
+
+/**
+ * "Divide" expression.
+ * 
+ * @since 1.1
+ */
+public class ASTDivide extends SimpleNode {
+    ASTDivide(int id) {
+        super(id);
+    }
+
+    public ASTDivide() {
+        super(ExpressionParserTreeConstants.JJTDIVIDE);
+    }
+
+    public ASTDivide(Object[] nodes) {
+        super(ExpressionParserTreeConstants.JJTDIVIDE);
+        int len = nodes.length;
+        for (int i = 0; i < len; i++) {
+            jjtAddChild(wrapChild(nodes[i]), i);
+        }
+        
+        connectChildren();
+    }
+
+    public ASTDivide(Collection nodes) {
+        super(ExpressionParserTreeConstants.JJTDIVIDE);
+        int len = nodes.size();
+        Iterator it = nodes.iterator();
+        for (int i = 0; i < len; i++) {
+            jjtAddChild(wrapChild(it.next()), i);
+        }
+        
+        connectChildren();
+    }
+
+    @Override
+    protected Object evaluateNode(Object o) throws Exception {
+        int len = jjtGetNumChildren();
+        if (len == 0) {
+            return null;
+        }
+
+        Double result = null;
+        for (int i = 0; i < len; i++) {
+            Number val = (Number) evaluateChild(i, o);
+
+            if (val == null) {
+                return null;
+            }
+
+            result = (i == 0) ? val.doubleValue() : result / val.doubleValue();
+        }
+
+        return result;
+    }
+
+    /**
+     * Creates a copy of this expression node, without copying children.
+     */
+    @Override
+    public Expression shallowCopy() {
+        return new ASTDivide(id);
+    }
+
+    @Override
+    protected String getExpressionOperator(int index) {
+        return "/";
+    }
+
+    @Override
+    public int getType() {
+        return Expression.DIVIDE;
+    }
+
+    @Override
+    public void jjtClose() {
+        super.jjtClose();
+        flattenTree();
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTEqual.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTEqual.java?rev=920884&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTEqual.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTEqual.java Tue Mar  9 14:16:07 2010
@@ -0,0 +1,138 @@
+/*****************************************************************
+ *   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.cayenne.exp.parser;
+
+import java.util.List;
+
+import org.apache.cayenne.exp.Expression;
+
+/**
+ * "Equal To" expression.
+ * 
+ * @since 1.1
+ */
+public class ASTEqual extends ConditionNode {
+    
+    /**
+     * Constructor used by expression parser. Do not invoke directly.
+     */
+    ASTEqual(int id) {
+        super(id);
+    }
+
+    public ASTEqual() {
+        super(ExpressionParserTreeConstants.JJTEQUAL);
+    }
+
+    /**
+     * Creates "Equal To" expression.
+     */
+    public ASTEqual(ASTPath path, Object value) {
+        super(ExpressionParserTreeConstants.JJTEQUAL);
+        jjtAddChild(path, 0);
+        jjtAddChild(new ASTScalar(value), 1);
+        connectChildren();
+    }
+
+    @Override
+    protected Object evaluateNode(Object o) throws Exception {
+        int len = jjtGetNumChildren();
+        if (len != 2) {
+            return Boolean.FALSE;
+        }
+
+        Object o1 = evaluateChild(0, o);
+        Object o2 = evaluateChild(1, o);
+
+        return evaluateImpl(o1, o2);
+    }
+    
+    /**
+     * Compares two objects, if one of them is array, 'in' operation is performed
+     */
+    static boolean evaluateImpl(Object o1, Object o2) {
+        // TODO: maybe we need a comparison "strategy" here, instead of
+        // a switch of all possible cases? ... there were other requests for
+        // more relaxed type-unsafe comparison (e.g. numbers to strings)
+        
+        if (o1 == null && o2 == null) {
+            return true;
+        }
+        else if (o1 != null) {
+            /**
+             * Per CAY-419 we perform 'in' comparison if one object is a list,
+             * and other is not
+             */
+            if (o1 instanceof List && !(o2 instanceof List)) {
+                for (Object element : ((List<?>) o1)) {
+                    if (element != null && evaluateAtomic(element, o2)) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+            if (o2 instanceof List && !(o1 instanceof List)) {
+                for (Object element : ((List<?>) o2)) {
+                    if (element != null && evaluateAtomic(element, o1)) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+            
+            return evaluateAtomic(o1, o2);
+        }
+        return false;
+    }
+    
+    /**
+     * Compares two objects. They must not be null
+     */
+    static boolean evaluateAtomic(Object o1, Object o2) {
+        return o1.equals(o2);
+    }
+
+    /**
+     * Creates a copy of this expression node, without copying children.
+     */
+    @Override
+    public Expression shallowCopy() {
+        return new ASTEqual(id);
+    }
+
+    @Override
+    protected String getExpressionOperator(int index) {
+        return "=";
+    }
+    
+    @Override
+    protected String getEJBQLExpressionOperator(int index) {
+    	if (jjtGetChild(1) instanceof ASTScalar && ((ASTScalar) jjtGetChild(1)).getValue() == null) {
+    		//for ejbql, we need "is null" instead of "= null"
+    		return "is";
+    	}
+    	return getExpressionOperator(index);
+    }
+
+    @Override
+    public int getType() {
+        return Expression.EQUAL_TO;
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTFalse.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTFalse.java?rev=920884&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTFalse.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTFalse.java Tue Mar  9 14:16:07 2010
@@ -0,0 +1,68 @@
+/*****************************************************************
+ *   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.cayenne.exp.parser;
+
+import org.apache.cayenne.exp.Expression;
+
+/**
+ * Boolean false expression element
+ * 
+ * Notice that there is one ASTTrue and one ASTFalse instead of a ASTBoolean with a
+ * Boolean value. The main reason for doing this is that a common ASTBoolean will have
+ * operand count of 1 and that will default to a prepared statmenet like " where ? and
+ * (...)", but we only need " where true and (...)".
+ * 
+ * @see ASTTrue
+ * @since 3.0
+ */
+public class ASTFalse extends ConditionNode {
+
+    /**
+     * Constructor used by expression parser. Do not invoke directly.
+     */
+    ASTFalse(int id) {
+        super(id);
+    }
+
+    public ASTFalse() {
+        super(ExpressionParserTreeConstants.JJTFALSE);
+    }
+
+    @Override
+    protected Object evaluateNode(Object o) throws Exception {
+        return Boolean.FALSE;
+    }
+
+    @Override
+    protected String getExpressionOperator(int index) {
+        throw new UnsupportedOperationException("No operator for '"
+                + ExpressionParserTreeConstants.jjtNodeName[id]
+                + "'");
+    }
+
+    @Override
+    public Expression shallowCopy() {
+        return new ASTFalse(id);
+    }
+
+    @Override
+    public int getType() {
+        return Expression.FALSE;
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTGreater.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTGreater.java?rev=920884&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTGreater.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTGreater.java Tue Mar  9 14:16:07 2010
@@ -0,0 +1,86 @@
+/*****************************************************************
+ *   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.cayenne.exp.parser;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.util.ConversionUtil;
+
+/**
+ * "Greate Than" expression.
+ * 
+ */
+public class ASTGreater extends ConditionNode {
+
+    /**
+     * Constructor used by expression parser. Do not invoke directly.
+     */
+    ASTGreater(int id) {
+        super(id);
+    }
+
+    public ASTGreater() {
+        super(ExpressionParserTreeConstants.JJTGREATER);
+    }
+
+    public ASTGreater(ASTPath path, Object value) {
+        super(ExpressionParserTreeConstants.JJTGREATER);
+        jjtAddChild(path, 0);
+        jjtAddChild(new ASTScalar(value), 1);
+        connectChildren();
+    }
+
+    @Override
+    protected Object evaluateNode(Object o) throws Exception {
+        int len = jjtGetNumChildren();
+        if (len != 2) {
+            return Boolean.FALSE;
+        }
+
+        Comparable c1 = ConversionUtil.toComparable(evaluateChild(0, o));
+        if (c1 == null) {
+            return Boolean.FALSE;
+        }
+
+        Comparable c2 = ConversionUtil.toComparable(evaluateChild(1, o));
+        if (c2 == null) {
+            return Boolean.FALSE;
+        }
+
+        return c1.compareTo(c2) > 0 ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Creates a copy of this expression node, without copying children.
+     */
+    @Override
+    public Expression shallowCopy() {
+        return new ASTGreater(id);
+    }
+
+    @Override
+    protected String getExpressionOperator(int index) {
+        return ">";
+    }
+
+    @Override
+    public int getType() {
+        return Expression.GREATER_THAN;
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTGreaterOrEqual.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTGreaterOrEqual.java?rev=920884&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTGreaterOrEqual.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTGreaterOrEqual.java Tue Mar  9 14:16:07 2010
@@ -0,0 +1,87 @@
+/*****************************************************************
+ *   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.cayenne.exp.parser;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.util.ConversionUtil;
+
+/**
+ * "Greater Than Or Equal To" expression.
+ * 
+ * @since 1.1
+ */
+public class ASTGreaterOrEqual extends ConditionNode {
+
+    /**
+     * Constructor used by expression parser. Do not invoke directly.
+     */
+    ASTGreaterOrEqual(int id) {
+        super(id);
+    }
+    
+    public ASTGreaterOrEqual() {
+        super(ExpressionParserTreeConstants.JJTGREATEROREQUAL);
+    }
+
+    public ASTGreaterOrEqual(ASTPath path, Object value) {
+        super(ExpressionParserTreeConstants.JJTGREATEROREQUAL);
+        jjtAddChild(path, 0);
+        jjtAddChild(new ASTScalar(value), 1);
+        connectChildren();
+    }
+
+    @Override
+    protected Object evaluateNode(Object o) throws Exception {
+        int len = jjtGetNumChildren();
+        if (len != 2) {
+            return Boolean.FALSE;
+        }
+
+        Comparable c1 = ConversionUtil.toComparable(evaluateChild(0, o));
+        if (c1 == null) {
+            return Boolean.FALSE;
+        }
+
+        Comparable c2 = ConversionUtil.toComparable(evaluateChild(1, o));
+        if (c2 == null) {
+            return Boolean.FALSE;
+        }
+
+        return c1.compareTo(c2) >= 0 ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Creates a copy of this expression node, without copying children.
+     */
+    @Override
+    public Expression shallowCopy() {
+        return new ASTGreaterOrEqual(id);
+    }
+
+    @Override
+    protected String getExpressionOperator(int index) {
+        return ">=";
+    }
+
+    @Override
+    public int getType() {
+        return Expression.GREATER_THAN_EQUAL_TO;
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTIn.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTIn.java?rev=920884&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTIn.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTIn.java Tue Mar  9 14:16:07 2010
@@ -0,0 +1,127 @@
+/*****************************************************************
+ *   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.cayenne.exp.parser;
+
+import java.util.Collection;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.commons.collections.Transformer;
+
+/**
+ * "In" expression.
+ * 
+ */
+public class ASTIn extends ConditionNode {
+
+    /**
+     * Constructor used by expression parser. Do not invoke directly.
+     */
+    ASTIn(int id) {
+        super(id);
+    }
+
+    public ASTIn() {
+        super(ExpressionParserTreeConstants.JJTIN);
+    }
+
+    public ASTIn(ASTPath path, ASTList list) {
+        super(ExpressionParserTreeConstants.JJTIN);
+        jjtAddChild(path, 0);
+        jjtAddChild(list, 1);
+        connectChildren();
+    }
+
+    @Override
+    protected Object evaluateNode(Object o) throws Exception {
+        int len = jjtGetNumChildren();
+        if (len != 2) {
+            return Boolean.FALSE;
+        }
+
+        Object o1 = evaluateChild(0, o);
+        if (o1 == null) {
+            return Boolean.FALSE;
+        }
+
+        Object[] objects = (Object[]) evaluateChild(1, o);
+        if (objects == null) {
+            return Boolean.FALSE;
+        }
+    
+        int size = objects.length;
+        for (int i = 0; i < size; i++) {
+            if (objects[i] != null) {
+                if (o1 instanceof Collection) {
+                	/* handle the case where we have a collection of objects */
+                	for (Object obj : (Collection) o1) {
+                    	if (ASTEqual.evaluateAtomic(obj, objects[i])) {
+                            return Boolean.TRUE;
+                    	}
+                	}
+                }
+                else {
+                	if (ASTEqual.evaluateAtomic(o1, objects[i])) {
+                        return Boolean.TRUE;
+                	}
+                }
+            }
+        }
+
+        return Boolean.FALSE;
+    }
+
+    /**
+     * Creates a copy of this expression node, without copying children.
+     */
+    @Override
+    public Expression shallowCopy() {
+        return new ASTIn(id);
+    }
+
+    @Override
+    protected String getExpressionOperator(int index) {
+        return "in";
+    }
+
+    @Override
+    public int getType() {
+        return Expression.IN;
+    }
+
+    @Override
+    protected Object transformExpression(Transformer transformer) {
+        Object transformed = super.transformExpression(transformer);
+        
+        // transform empty ASTIn to ASTFalse
+        if (transformed instanceof ASTIn) {
+            ASTIn exp = (ASTIn) transformed;
+            if (exp.jjtGetNumChildren() == 2) {
+                ASTList list = (ASTList) exp.jjtGetChild(1);
+                Object[] objects = (Object[]) list.evaluate(null);
+                if (objects.length == 0) {
+                    transformed = new ASTFalse();
+                }
+            }
+        }
+
+        return transformed;
+    }
+
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTLess.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTLess.java?rev=920884&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTLess.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTLess.java Tue Mar  9 14:16:07 2010
@@ -0,0 +1,86 @@
+/*****************************************************************
+ *   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.cayenne.exp.parser;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.util.ConversionUtil;
+
+/**
+ * "Less Then" expression.
+ * 
+ * @since 1.1
+ */
+public class ASTLess extends ConditionNode {
+    /**
+     * Constructor used by expression parser. Do not invoke directly.
+     */
+    ASTLess(int id) {
+        super(id);
+    }
+
+    public ASTLess() {
+        super(ExpressionParserTreeConstants.JJTLESS);
+    }
+
+    public ASTLess(ASTPath path, Object value) {
+        super(ExpressionParserTreeConstants.JJTLESS);
+        jjtAddChild(path, 0);
+        jjtAddChild(new ASTScalar(value), 1);
+        connectChildren();
+    }
+
+    @Override
+    protected Object evaluateNode(Object o) throws Exception {
+        int len = jjtGetNumChildren();
+        if (len != 2) {
+            return Boolean.FALSE;
+        }
+
+        Comparable c1 = ConversionUtil.toComparable(evaluateChild(0, o));
+        if (c1 == null) {
+            return Boolean.FALSE;
+        }
+
+        Comparable c2 = ConversionUtil.toComparable(evaluateChild(1, o));
+        if (c2 == null) {
+            return Boolean.FALSE;
+        }
+
+        return c1.compareTo(c2) < 0 ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Creates a copy of this expression node, without copying children.
+     */
+    @Override
+    public Expression shallowCopy() {
+        return new ASTLess(id);
+    }
+
+    @Override
+    protected String getExpressionOperator(int index) {
+        return "<";
+    }
+
+    @Override
+    public int getType() {
+        return Expression.LESS_THAN;
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTLessOrEqual.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTLessOrEqual.java?rev=920884&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTLessOrEqual.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTLessOrEqual.java Tue Mar  9 14:16:07 2010
@@ -0,0 +1,87 @@
+/*****************************************************************
+ *   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.cayenne.exp.parser;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.util.ConversionUtil;
+
+/**
+ * "Less than or equal to" expression.
+ * 
+ * @since 1.1
+ */
+public class ASTLessOrEqual extends ConditionNode {
+
+    /**
+     * Constructor used by expression parser. Do not invoke directly.
+     */
+    ASTLessOrEqual(int id) {
+        super(id);
+    }
+
+    public ASTLessOrEqual() {
+        super(ExpressionParserTreeConstants.JJTLESSOREQUAL);
+    }
+
+    public ASTLessOrEqual(ASTPath path, Object value) {
+        super(ExpressionParserTreeConstants.JJTLESSOREQUAL);
+        jjtAddChild(path, 0);
+        jjtAddChild(new ASTScalar(value), 1);
+        connectChildren();
+    }
+
+    @Override
+    protected Object evaluateNode(Object o) throws Exception {
+        int len = jjtGetNumChildren();
+        if (len != 2) {
+            return Boolean.FALSE;
+        }
+
+        Comparable c1 = ConversionUtil.toComparable(evaluateChild(0, o));
+        if (c1 == null) {
+            return Boolean.FALSE;
+        }
+
+        Comparable c2 = ConversionUtil.toComparable(evaluateChild(1, o));
+        if (c2 == null) {
+            return Boolean.FALSE;
+        }
+
+        return c1.compareTo(c2) <= 0 ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Creates a copy of this expression node, without copying children.
+     */
+    @Override
+    public Expression shallowCopy() {
+        return new ASTLessOrEqual(id);
+    }
+
+    @Override
+    protected String getExpressionOperator(int index) {
+        return "<=";
+    }
+
+    @Override
+    public int getType() {
+        return Expression.LESS_THAN_EQUAL_TO;
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTLike.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTLike.java?rev=920884&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTLike.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTLike.java Tue Mar  9 14:16:07 2010
@@ -0,0 +1,67 @@
+/*****************************************************************
+ *   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.cayenne.exp.parser;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionException;
+
+/**
+ * "Like" expression.
+ * 
+ */
+public class ASTLike extends PatternMatchNode {
+    ASTLike(int id) {
+        super(id, false);
+    }
+
+    public ASTLike() {
+        super(ExpressionParserTreeConstants.JJTLIKE, false);
+    }
+
+    public ASTLike(ASTPath path, Object pattern) {
+        super(ExpressionParserTreeConstants.JJTLIKE, false);
+        jjtAddChild(path, 0);
+        jjtAddChild(new ASTScalar(pattern), 1);
+        connectChildren();
+    }
+
+    @Override
+    protected Object evaluateNode(Object o) throws Exception {
+        throw new ExpressionException("Cannot evaluate LIKE on GWT client side");
+    }
+
+    /**
+     * Creates a copy of this expression node, without copying children.
+     */
+    @Override
+    public Expression shallowCopy() {
+        return new ASTLike(id);
+    }
+
+    @Override
+    protected String getExpressionOperator(int index) {
+        return "like";
+    }
+
+    @Override
+    public int getType() {
+        return Expression.LIKE;
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTLikeIgnoreCase.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTLikeIgnoreCase.java?rev=920884&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTLikeIgnoreCase.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTLikeIgnoreCase.java Tue Mar  9 14:16:07 2010
@@ -0,0 +1,72 @@
+/*****************************************************************
+ *   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.cayenne.exp.parser;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionException;
+
+/**
+ * "Case insensitive like" expression.
+ * 
+ */
+public class ASTLikeIgnoreCase extends IgnoreCaseNode {
+    ASTLikeIgnoreCase(int id) {
+        super(id, true);
+    }
+
+    public ASTLikeIgnoreCase() {
+        super(ExpressionParserTreeConstants.JJTLIKEIGNORECASE, true);
+    }
+
+    public ASTLikeIgnoreCase(ASTPath path, Object pattern) {
+        super(ExpressionParserTreeConstants.JJTLIKEIGNORECASE, true);
+        jjtAddChild(path, 0);
+        jjtAddChild(new ASTScalar(pattern), 1);
+        connectChildren();
+    }
+
+    @Override
+    protected Object evaluateNode(Object o) throws Exception {
+    	throw new ExpressionException("Cannot evaluate LIKE on GWT client side");
+    }
+
+    /**
+     * Creates a copy of this expression node, without copying children.
+     */
+    @Override
+    public Expression shallowCopy() {
+        return new ASTLikeIgnoreCase(id);
+    }
+
+    @Override
+    protected String getExpressionOperator(int index) {
+        return "likeIgnoreCase";
+    }
+
+    @Override
+    public int getType() {
+        return Expression.LIKE_IGNORE_CASE;
+    }
+    
+    @Override
+    protected String getEJBQLExpressionOperator(int index) {
+        return "like";
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTList.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTList.java?rev=920884&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTList.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTList.java Tue Mar  9 14:16:07 2010
@@ -0,0 +1,164 @@
+/*****************************************************************
+ *   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.cayenne.exp.parser;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.cayenne.exp.Expression;
+
+/**
+ * A leaf expression representing an immutable collection of values.
+ * 
+ * @since 1.1
+ */
+public class ASTList extends SimpleNode {
+    protected Object[] values;
+
+    ASTList(int id) {
+        super(id);
+    }
+
+    public ASTList() {
+        super(ExpressionParserTreeConstants.JJTLIST);
+    }
+
+    /**
+     * Initializes a list expression with an Object[].
+     */
+    public ASTList(Object[] objects) {
+        super(ExpressionParserTreeConstants.JJTLIST);
+        setValues(objects);
+    }
+
+    /**
+     * Initializes a list expression with a Java Collection
+     */
+    public ASTList(Collection objects) {
+        super(ExpressionParserTreeConstants.JJTLIST);
+        setValues(objects);
+    }
+
+    /**
+     * Initializes a list expression with a Java Iterator.
+     */
+    public ASTList(Iterator objects) {
+        super(ExpressionParserTreeConstants.JJTLIST);
+        setValues(objects);
+    }
+
+    /**
+     * Creates a copy of this expression node, without copying children.
+     */
+    @Override
+    public Expression shallowCopy() {
+        return new ASTList(id);
+    }
+
+    @Override
+    protected Object evaluateNode(Object o) throws Exception {
+        return values;
+    }
+
+    @Override
+    public int getType() {
+        return Expression.LIST;
+    }
+
+    @Override
+    protected String getExpressionOperator(int index) {
+        return ",";
+    }
+
+    @Override
+    public int getOperandCount() {
+        return 1;
+    }
+
+    @Override
+    public Object getOperand(int index) {
+        if (index == 0) {
+            return values;
+        }
+
+        throw new ArrayIndexOutOfBoundsException(index);
+    }
+
+    @Override
+    public void setOperand(int index, Object value) {
+        if (index != 0) {
+            throw new ArrayIndexOutOfBoundsException(index);
+        }
+
+        setValues(value);
+    }
+
+    /**
+     * Sets an internal collection of values. Value argument
+     * can be an Object[], a Collection or an iterator.
+     */
+    protected void setValues(Object value) {
+        if (value == null) {
+            this.values = null;
+        }
+        else if (value instanceof Object[]) {
+            this.values = (Object[]) value;
+        }
+        else if (value instanceof Collection) {
+            this.values = ((Collection) value).toArray();
+        }
+        else if (value instanceof Iterator) {
+            List values = new ArrayList();
+            Iterator it = (Iterator) value;
+            while (it.hasNext()) {
+                values.add(it.next());
+            }
+
+            this.values = values.toArray();
+        }
+        else {
+            throw new IllegalArgumentException(
+                "Invalid value class '"
+                    + value.getClass().getName()
+                    + "', expected null, Object[], Collection, Iterator");
+        }
+    }
+
+    @Override
+    public void jjtClose() {
+        super.jjtClose();
+
+        // For backwards compatibility set a List value wrapping the nodes.
+        // or maybe we should rewrite the parser spec to insert children
+        // directly into internal collection?
+        int size = jjtGetNumChildren();
+        Object[] listValue = new Object[size];
+        for (int i = 0; i < size; i++) {
+            listValue[i] = unwrapChild(jjtGetChild(i));
+        }
+
+        setValues(listValue);
+
+        // clean children - we are not supposed to use them anymore
+        children = null;
+    }
+}

Added: cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTMultiply.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTMultiply.java?rev=920884&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTMultiply.java (added)
+++ cayenne/sandbox/cayenne-gwt/src/main/resources/org/apache/cayenne/query/emul/org/apache/cayenne/exp/parser/ASTMultiply.java Tue Mar  9 14:16:07 2010
@@ -0,0 +1,105 @@
+/*****************************************************************
+ *   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.cayenne.exp.parser;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.cayenne.exp.Expression;
+
+/**
+ * "Multiply" expression.
+ * 
+ * @since 1.1
+ */
+public class ASTMultiply extends SimpleNode {
+    ASTMultiply(int id) {
+        super(id);
+    }
+
+    public ASTMultiply() {
+        super(ExpressionParserTreeConstants.JJTMULTIPLY);
+    }
+
+    public ASTMultiply(Object[] nodes) {
+        super(ExpressionParserTreeConstants.JJTMULTIPLY);
+        int len = nodes.length;
+        for (int i = 0; i < len; i++) {
+            jjtAddChild(wrapChild(nodes[i]), i);
+        }
+        
+        connectChildren();
+    }
+
+    public ASTMultiply(Collection nodes) {
+        super(ExpressionParserTreeConstants.JJTMULTIPLY);
+        int len = nodes.size();
+        Iterator it = nodes.iterator();
+        for (int i = 0; i < len; i++) {
+            jjtAddChild(wrapChild(it.next()), i);
+        }
+    }
+
+    @Override
+    protected Object evaluateNode(Object o) throws Exception {
+        int len = jjtGetNumChildren();
+        if (len == 0) {
+            return null;
+        }
+
+        Double result = null;
+        for (int i = 0; i < len; i++) {
+            Number val = (Number) evaluateChild(i, o);
+
+            if (val == null) {
+                return null;
+            }
+
+            result = (i == 0) ? val.doubleValue() : result * val.doubleValue();
+        }
+
+        return result;
+    }
+
+    /**
+     * Creates a copy of this expression node, without copying children.
+     */
+    @Override
+    public Expression shallowCopy() {
+        return new ASTMultiply(id);
+    }
+
+    @Override
+    protected String getExpressionOperator(int index) {
+        return "*";
+    }
+
+    @Override
+    public int getType() {
+        return Expression.MULTIPLY;
+    }
+
+    @Override
+    public void jjtClose() {
+        super.jjtClose();
+        flattenTree();
+    }
+}