Index: trunk/fmgVen/src/com/fmguler/ven/Criteria.java
===================================================================
--- trunk/fmgVen/src/com/fmguler/ven/Criteria.java	(revision 30)
+++ trunk/fmgVen/src/com/fmguler/ven/Criteria.java	(revision 30)
@@ -0,0 +1,343 @@
+/*
+ *  fmgVen - A Convention over Configuration Java ORM Tool
+ *  Copyright 2011 Fatih Mehmet Güler
+ * 
+ *  Licensed 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.
+ *  under the License.
+ */
+package com.fmguler.ven;
+
+import com.fmguler.ven.util.Convert;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Stack;
+
+/**
+ * Criteria object, used to filter the result of a query according to some criteria.
+ * <p>
+ * Can be used in two modes; as string criteria or typed criteria.
+ * The string criteria is used like;
+ * <pre>
+ * new Criteria().add("and SomeDomainObject.anotherDomainObjects.name like :p1").param("p1", "a%");
+ * </pre>
+ * And the typed criteria is used like;
+ * <pre>
+ * new Criteria().eq(attr,value).like(attr,value).and().gt(attr, value).or().orderAsc(attr).orderDesc(attr).limit(limit, offset);
+ * </pre>
+ *
+ * This criteria object is used to filter SQL results by adding the "Criteria.criteriaToSQL()" output to the where clause.
+ * 
+ * @author Fatih Mehmet Güler
+ */
+public class Criteria {
+    private StringBuffer criteriaStringBuffer = new StringBuffer(); //for string criteria
+    private LinkedList criterionList = new LinkedList(); //for typed criteria
+    private Map parameters = new HashMap(); //the parameters used in criteria string
+    private int limit = 20;
+    private int offset = 0;
+    int paramCount = 0;
+
+    //--------------------------------------------------------------------------
+    //String Criteria Methods
+    /**
+     * Add a criteria string
+     */
+    public Criteria add(String criteriaString) {
+        this.criteriaStringBuffer.append(" ").append(criteriaString);
+        return this;
+    }
+
+    /**
+     * Add the parameter used in criteria string
+     */
+    public Criteria param(String parameter, Object value) {
+        this.parameters.put(parameter, value);
+        return this;
+    }
+
+    /**
+     * Converts criteria string to SQL
+     * @return the criteria string as SQL where clause
+     */
+    public String criteriaStringToSQL() {
+        StringBuffer resultBuffer = new StringBuffer();
+        String criteriaString = criteriaStringBuffer.toString();
+        criteriaString = criteriaString.replaceAll("\\(", "\\( ");
+        criteriaString = criteriaString.replaceAll("\\)", " \\)");
+
+        String[] parts = criteriaString.split(" ");
+        for (int i = 0; i < parts.length; i++) {
+            if (!parts[i].startsWith(":") && parts[i].indexOf(".") >= 0) {
+                int lastDot = parts[i].lastIndexOf('.');
+                resultBuffer.append(" ");
+                int u = parts[i].length();
+                resultBuffer.append(Convert.toDB(parts[i].substring(0, lastDot).replace('.', '_')));
+                resultBuffer.append(Convert.toDB(parts[i].substring(lastDot, u)));
+            } else {
+                resultBuffer.append(" ").append(parts[i]);
+            }
+        }
+        return resultBuffer.toString();
+    }
+
+    /**
+     * @return the parameter map
+     */
+    public Map getParameters() {
+        return parameters;
+    }
+
+    //--------------------------------------------------------------------------
+    //Typed Criteria Methods
+    /**
+     * Add a criterion where an attribue equals a value (SQL = operator)
+     */
+    public Criteria eq(String attribute, String value) {
+        criterionList.add(new Criterion(attribute, Criterion.OP_EQUALS, value));
+        return this;
+    }
+
+    /**
+     * Add a criterion where an attribue is like a value (SQL like operator)
+     */
+    public Criteria like(String attribute, String value) {
+        criterionList.add(new Criterion(attribute, Criterion.OP_LIKE, value));
+        return this;
+    }
+
+    /**
+     * Add a criterion where an attribue is similar to a value (SQL similar to operator)
+     */
+    public Criteria similarto(String attribute, String value) {
+        criterionList.add(new Criterion(attribute, Criterion.OP_SIMILAR_TO, value));
+        return this;
+    }
+
+    /**
+     * Add a criterion where an attribue is greater than a value (SQL > operator)
+     */
+    public Criteria gt(String attribute, String value) {
+        criterionList.add(new Criterion(attribute, Criterion.OP_GREATER_THAN, value));
+        return this;
+    }
+
+    /**
+     * Add a criterion where an attribue is less than a value (SQL < operator)
+     */
+    public Criteria lt(String attribute, String value) {
+        criterionList.add(new Criterion(attribute, Criterion.OP_LESS_THAN, value));
+        return this;
+    }
+
+    /**
+     * Add a criterion where an attribue is null (SQL is null operator)
+     */
+    public Criteria isNull(String attribute) {
+        criterionList.add(new Criterion(attribute, Criterion.OP_ISNULL, null));
+        return this;
+    }
+
+    /**
+     * Add: order by attribute asc
+     */
+    public Criteria orderAsc(String attribute) {
+        //Not implemented yet.
+        return this;
+    }
+
+    /**
+     * Add: order by attribute desc
+     */
+    public Criteria orderDesc(String attribute) {
+        //Not implemented yet.
+        return this;
+    }
+
+    /**
+     * Add limit and offset to the clause
+     */
+    public Criteria limit(int limit, int offset) {
+        this.limit = limit;
+        this.offset = offset;
+        return this;
+    }
+
+    //--------------------------------------------------------------------------
+    //Connectives
+    /**
+     * Connect previous two criteria with logical and
+     * (as in postfix notation)
+     */
+    public Criteria and() {
+        criterionList.add(new Criterion(Criterion.CONN_AND));
+        return this;
+    }
+
+    /**
+     * Connect previous two criteria with logical or
+     * (as in postfix notation)
+     */
+    public Criteria or() {
+        criterionList.add(new Criterion(Criterion.CONN_OR));
+        return this;
+    }
+
+    /**
+     * Connect previous criterion with logical not
+     * (as in postfix notation)
+     */
+    public Criteria not() {
+        criterionList.add(new Criterion(Criterion.CONN_NOT));
+        return this;
+    }
+
+    /**
+     * Converts typed criteria to SQL
+     * @return the typed criteria as SQL where clause
+     */
+    public String criteriaToSQL() {
+        LinkedList clone = (LinkedList)criterionList.clone();
+        Stack stack = new Stack();
+        while (!clone.isEmpty()) {
+            Criterion criterion = (Criterion)clone.removeFirst();
+            if (!criterion.isConnective()) {
+                String s = "(" + convertOperatorToSQL(criterion) + ")";
+                stack.push(s);
+            } else {
+                String conn = criterion.connective;
+                if (conn.equals(Criterion.CONN_AND)) {
+                    String s1 = (String)stack.pop();
+                    String s2 = (String)stack.pop();
+                    String sr = "(" + s1 + " and " + s2 + ")";
+                    stack.push(sr);
+                } else if (conn.equals(Criterion.CONN_OR)) {
+                        String s1 = (String)stack.pop();
+                        String s2 = (String)stack.pop();
+                        String sr = "(" + s1 + " or " + s2 + ")";
+                        stack.push(sr);
+                    } else if (conn.equals(Criterion.CONN_NOT)) {
+                            String s = (String)stack.pop();
+                            String sr = "not (" + s + ")";
+                            stack.push(sr);
+                        }
+            }
+        }
+
+        if (stack.isEmpty()) return "1=1";
+
+        String result = (String)stack.pop();
+        return result;
+    }
+
+    //convert the attribute-operator-value criterion to SQL
+    private String convertOperatorToSQL(Criterion criterion) {
+        String attribute = convertAttributeToAlias(criterion.attribute);
+        String operator = criterion.operator;
+        Object value = criterion.value;
+        String result = "";
+
+        if (value == null) {
+            //no value e.g. is null operator
+            result = attribute + " " + operator;
+        } else {
+            String paramName = genParamName();
+            parameters.put(paramName, value);
+            result = attribute + " " + operator + " :" + paramName + "";
+        }
+
+        return result;
+    }
+
+    //convert attribute to SQL alias
+    protected String convertAttributeToAlias(String attribute) {
+        //we convert like: x.y.z.t to x_y_z.t
+        StringBuffer resultBuffer = new StringBuffer();
+        int lastDot = attribute.lastIndexOf('.');
+        resultBuffer.append(" ");
+        int u = attribute.length();
+        resultBuffer.append(Convert.toDB(attribute.substring(0, lastDot).replace('.', '_')));
+        resultBuffer.append(Convert.toDB(attribute.substring(lastDot, u)));
+        return resultBuffer.toString();
+    }
+
+    //generate parameter for typed criteria
+    private String genParamName() {
+        return "__p" + paramCount++;
+    }
+
+    //test the criteria object
+    public static void main(String[] args) {
+        Criteria criteria = new Criteria() //criteria object
+                .like("SomeDomainObject.anotherDomainObjects.name", "a%") //attribute like value
+                .eq("SomeDomainObject.name", "sdo1") //attribute equals value
+                .and() //connect previous criteria with and
+                .isNull("SomeDomainObject.description") //attribute is null
+                .or(); //connect previous criteria with and
+
+        //print the resulting where clause SQL
+        System.out.println(criteria.criteriaToSQL());
+
+        //the result is;
+        //(( some_domain_object.description is null) or (( some_domain_object.name = :__p1) and ( some_domain_object_another_domain_objects.name like :__p0)))
+    }
+}
+
+/**
+ * Each criterion used in the criteria.
+ * Used to hold attribute-operator-value triplet.
+ * Used internally.
+ * @author Fatih Mehmet Güler
+ */
+class Criterion {
+    //available logical connectives
+    public static final String CONN_AND = "and";
+    public static final String CONN_OR = "or";
+    public static final String CONN_NOT = "not";
+    //available operators
+    public static final String OP_EQUALS = "=";
+    public static final String OP_LESS_THAN = "<";
+    public static final String OP_GREATER_THAN = ">";
+    public static final String OP_LIKE = "like";
+    public static final String OP_SIMILAR_TO = "similar to";
+    public static final String OP_NOT = "not";
+    public static final String OP_ISNULL = "is null";
+    //attribute-operator-value triplet
+    public String attribute;
+    public String operator;
+    public Object value;
+    //logical connective
+    public String connective = null;
+
+    public Criterion(String attribute, String operator, Object value) {
+        this.attribute = attribute;
+        this.operator = operator;
+        this.value = value;
+    }
+
+    public Criterion(String connective) {
+        this.connective = connective;
+    }
+
+    public boolean isConnective() {
+        return connective != null;
+    }
+
+    /**
+     * @return string representation of this criterion
+     */
+    public String toString() {
+        if (isConnective()) return connective;
+        return attribute + " " + operator + " " + value;
+    }
+}
Index: trunk/fmgVen/src/com/fmguler/ven/Ven.java
===================================================================
--- trunk/fmgVen/src/com/fmguler/ven/Ven.java	(revision 29)
+++ trunk/fmgVen/src/com/fmguler/ven/Ven.java	(revision 30)
@@ -97,4 +97,26 @@
 
     /**
+     * List the objects of the specified objectClass type, filtering according to some criteria.
+     * <p>
+     * By default none of the associations will be retrieved.
+     * To include the object associations (retrieve the object graph) joins should be specified, e.g.
+     * <code>SomeObject.anotherObject</code>
+     * 
+     * @param objectClass the class of the objects to be retrieved
+     * @param joins the set of object graphs to be included with objects
+     * @param criteria to filter and order the result according to some criteria
+     * @return the list of objects including the specified associations filtered according to the specified criteria
+     */
+    public List list(Class objectClass, Set joins, Criteria criteria) {
+        String query = generator.generateSelectQuery(objectClass, joins);
+        query += " where 1=1 " + criteria.criteriaStringToSQL() + " and " + criteria.criteriaToSQL();
+
+        if (debug) System.out.println("Ven - SQL: " + query);
+
+        List result = mapper.list(query, criteria.getParameters(), objectClass);
+        return result;
+    }
+
+    /**
      * Save the object. If it has a non null (or non zero) "id" property it will be updated.
      * It will be inserted otherwise.
