svn commit: r792420 - in /ofbiz/trunk/framework/entity/src/org/ofbiz/entity: condition/ datasource/ finder/ jdbc/ model/

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r792420 - in /ofbiz/trunk/framework/entity/src/org/ofbiz/entity: condition/ datasource/ finder/ jdbc/ model/

jonesde
Author: jonesde
Date: Thu Jul  9 06:48:05 2009
New Revision: 792420

URL: http://svn.apache.org/viewvc?rev=792420&view=rev
Log:
Refactored implementation of view-entity entity-condition implementation to support the changes to the XSD and support the various new options; tested to work with the various cases in the entitymodel_view.xml file in the example component

Modified:
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/condition/EntityConditionBase.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/condition/EntityConditionValue.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/condition/EntityFieldValue.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/finder/ByConditionFinder.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelViewEntity.java

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/condition/EntityConditionBase.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/condition/EntityConditionBase.java?rev=792420&r1=792419&r2=792420&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/condition/EntityConditionBase.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/condition/EntityConditionBase.java Thu Jul  9 06:48:05 2009
@@ -23,7 +23,6 @@
 import java.util.List;
 import java.util.Map;
 
-import javolution.lang.Reusable;
 import javolution.util.FastList;
 import javolution.util.FastMap;
 
@@ -45,6 +44,7 @@
  * These can be used in various combinations using the EntityConditionList and EntityExpr objects.
  *
  */
+@SuppressWarnings("serial")
 public abstract class EntityConditionBase implements Serializable {
 
     public static final List emptyList = Collections.unmodifiableList(FastList.newInstance());

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/condition/EntityConditionValue.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/condition/EntityConditionValue.java?rev=792420&r1=792419&r2=792420&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/condition/EntityConditionValue.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/condition/EntityConditionValue.java Thu Jul  9 06:48:05 2009
@@ -33,6 +33,7 @@
  * Encapsulates operations between entities and entity fields. This is a immutable class.
  *
  */
+@SuppressWarnings("serial")
 public abstract class EntityConditionValue extends EntityConditionBase {
 
     public abstract ModelField getModelField(ModelEntity modelEntity);

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/condition/EntityFieldValue.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/condition/EntityFieldValue.java?rev=792420&r1=792419&r2=792420&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/condition/EntityFieldValue.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/condition/EntityFieldValue.java Thu Jul  9 06:48:05 2009
@@ -25,17 +25,20 @@
 import javolution.context.ObjectFactory;
 import javolution.lang.Reusable;
 
+import org.ofbiz.base.util.UtilValidate;
 import org.ofbiz.entity.GenericDelegator;
 import org.ofbiz.entity.GenericEntity;
 import org.ofbiz.entity.GenericModelException;
 import org.ofbiz.entity.config.DatasourceInfo;
 import org.ofbiz.entity.model.ModelEntity;
 import org.ofbiz.entity.model.ModelField;
+import org.ofbiz.entity.model.ModelViewEntity;
 
 /**
  * Encapsulates operations between entities and entity fields. This is a immutable class.
  *
  */
+@SuppressWarnings("serial")
 public class EntityFieldValue extends EntityConditionValue implements Reusable {
 
     protected static final ObjectFactory<EntityFieldValue> entityFieldValueFactory = new ObjectFactory<EntityFieldValue>() {
@@ -46,10 +49,18 @@
     };
 
     protected String fieldName = null;
+    protected String entityAlias = null;
+    protected ModelViewEntity modelViewEntity = null;
 
     public static EntityFieldValue makeFieldValue(String fieldName) {
         EntityFieldValue efv = EntityFieldValue.entityFieldValueFactory.object();
-        efv.init(fieldName);
+        efv.init(fieldName, null, null);
+        return efv;
+    }
+
+    public static EntityFieldValue makeFieldValue(String fieldName, String entityAlias, ModelViewEntity modelViewEntity) {
+        EntityFieldValue efv = EntityFieldValue.entityFieldValueFactory.object();
+        efv.init(fieldName, entityAlias, modelViewEntity);
         return efv;
     }
 
@@ -58,11 +69,13 @@
     /** @deprecated Use EntityFieldValue.makeFieldValue() instead */
     @Deprecated
     public EntityFieldValue(String fieldName) {
-    this.init(fieldName);
+        this.init(fieldName, null, null);
     }
 
-    public void init(String fieldName) {
+    public void init(String fieldName, String entityAlias, ModelViewEntity modelViewEntity) {
         this.fieldName = fieldName;
+        this.entityAlias = entityAlias;
+        this.modelViewEntity = modelViewEntity;
     }
 
     public void reset() {
@@ -92,7 +105,19 @@
 
     @Override
     public void addSqlValue(StringBuilder sql, Map<String, String> tableAliases, ModelEntity modelEntity, List<EntityConditionParam> entityConditionParams, boolean includeTableNamePrefix, DatasourceInfo datasourceInfo) {
-        sql.append(getColName(tableAliases, modelEntity, fieldName, includeTableNamePrefix, datasourceInfo));
+        if (this.modelViewEntity != null) {
+            if (UtilValidate.isNotEmpty(entityAlias)) {
+                ModelEntity memberModelEntity = modelViewEntity.getMemberModelEntity(entityAlias);
+                ModelField modelField = memberModelEntity.getField(fieldName);
+                sql.append(entityAlias);
+                sql.append(".");
+                sql.append(modelField.getColName());
+            } else {
+                sql.append(getColName(tableAliases, modelViewEntity, fieldName, includeTableNamePrefix, datasourceInfo));
+            }
+        } else {
+            sql.append(getColName(tableAliases, modelEntity, fieldName, includeTableNamePrefix, datasourceInfo));
+        }
     }
 
     @Override

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java?rev=792420&r1=792419&r2=792420&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/datasource/GenericDAO.java Thu Jul  9 06:48:05 2009
@@ -705,8 +705,8 @@
         if (orderBy != null) {
             orderByExpanded.addAll(orderBy);
         }
-        if (modelViewEntity != null && modelViewEntity.getByConditionFinder() != null) {
-            List<String> viewOrderBy = modelViewEntity.getByConditionFinder().getOrderByFieldList(FastMap.<String, Object>newInstance());
+        if (modelViewEntity != null) {
+            List<String> viewOrderBy = modelViewEntity.getViewEntityConditionOrderBy();
             if (viewOrderBy != null && viewOrderBy.size() > 0) {
                 orderByExpanded.addAll(viewOrderBy);
             }
@@ -745,9 +745,9 @@
         if (Debug.timingOn()) {
             long queryEndTime = System.currentTimeMillis();
             long queryTotalTime = queryEndTime - queryStartTime;
-            if (queryTotalTime > 150) {
+            // TODO remove comment: if (queryTotalTime > 150) {
                 Debug.logTiming("Ran query in " + queryTotalTime + " milli-seconds: " + sql, module);
-            }
+            //}
         }
         return new EntityListIterator(sqlP, modelEntity, selectFields, modelFieldTypeReader);
     }
@@ -764,8 +764,8 @@
         }
 
         String viewEntityCondWhereString = null;
-        if (modelViewEntity != null && modelViewEntity.getByConditionFinder() != null) {
-            EntityCondition viewWhereEntityCondition = modelViewEntity.getByConditionFinder().getWhereEntityCondition(FastMap.<String, Object>newInstance(), modelEntity, this.modelFieldTypeReader);
+        if (modelViewEntity != null) {
+            EntityCondition viewWhereEntityCondition = modelViewEntity.getViewEntityConditionWhere(this.modelFieldTypeReader);
             if (viewWhereEntityCondition != null) {
                 viewEntityCondWhereString = viewWhereEntityCondition.makeWhereString(modelEntity, whereEntityConditionParams, this.datasourceInfo);
             }
@@ -815,8 +815,8 @@
         }
         
         String viewEntityCondHavingString = null;
-        if (modelViewEntity != null && modelViewEntity.getByConditionFinder() != null) {
-            EntityCondition viewHavingEntityCondition = modelViewEntity.getByConditionFinder().getHavingEntityCondition(FastMap.<String, Object>newInstance(), modelEntity, this.modelFieldTypeReader);
+        if (modelViewEntity != null) {
+            EntityCondition viewHavingEntityCondition = modelViewEntity.getViewEntityConditionHaving(this.modelFieldTypeReader);
             if (viewHavingEntityCondition != null) {
                 viewEntityCondHavingString = viewHavingEntityCondition.makeWhereString(modelEntity, havingEntityConditionParams, this.datasourceInfo);
             }

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/finder/ByConditionFinder.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/finder/ByConditionFinder.java?rev=792420&r1=792419&r2=792420&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/finder/ByConditionFinder.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/finder/ByConditionFinder.java Thu Jul  9 06:48:05 2009
@@ -56,6 +56,11 @@
         } else if (conditionObjectElement != null) {
             this.whereCondition = new ConditionObject(conditionObjectElement);
         }
+
+        Element havingConditionListElement = UtilXml.firstChildElement(element, "having-condition-list");
+        if (havingConditionListElement != null) {
+            this.havingCondition = new ConditionList(havingConditionListElement);
+        }
     }
 
     @Override

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java?rev=792420&r1=792419&r2=792420&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java Thu Jul  9 06:48:05 2009
@@ -176,6 +176,10 @@
                     if (condBuffer.length() == 0) {
                         throw new GenericModelException("No view-link/join key-maps found for the " + viewLink.getEntityAlias() + " and the " + viewLink.getRelEntityAlias() + " member-entities of the " + modelViewEntity.getEntityName() + " view-entity.");
                     }
+                    
+                    // TODO add expression from entity-condition on view-link
+                    
+                    
                     restOfStatement.append(condBuffer.toString());
 
                     // don't put ending parenthesis

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelViewEntity.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelViewEntity.java?rev=792420&r1=792419&r2=792420&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelViewEntity.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/model/ModelViewEntity.java Thu Jul  9 06:48:05 2009
@@ -20,8 +20,10 @@
 
 import java.io.Serializable;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -30,11 +32,25 @@
 import javolution.util.FastMap;
 
 import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.ObjectType;
+import org.ofbiz.base.util.StringUtil;
+import org.ofbiz.base.util.UtilFormatOut;
 import org.ofbiz.base.util.UtilTimer;
 import org.ofbiz.base.util.UtilValidate;
 import org.ofbiz.base.util.UtilXml;
+import org.ofbiz.base.util.collections.FlexibleMapAccessor;
+import org.ofbiz.base.util.string.FlexibleStringExpander;
+import org.ofbiz.entity.condition.EntityComparisonOperator;
+import org.ofbiz.entity.condition.EntityCondition;
+import org.ofbiz.entity.condition.EntityFieldValue;
+import org.ofbiz.entity.condition.EntityFunction;
+import org.ofbiz.entity.condition.EntityJoinOperator;
 import org.ofbiz.entity.condition.EntityOperator;
 import org.ofbiz.entity.finder.ByConditionFinder;
+import org.ofbiz.entity.finder.EntityFinderUtil.Condition;
+import org.ofbiz.entity.finder.EntityFinderUtil.ConditionExpr;
+import org.ofbiz.entity.finder.EntityFinderUtil.ConditionList;
+import org.ofbiz.entity.finder.EntityFinderUtil.ConditionObject;
 import org.ofbiz.entity.jdbc.SqlJdbcUtil;
 import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
@@ -81,7 +97,7 @@
 
     protected Map<String, Map<String, ModelConversion>> conversions = FastMap.newInstance();
     
-    protected ByConditionFinder byConditionFinder = null;
+    protected ViewEntityCondition viewEntityCondition = null;
 
     public ModelViewEntity(ModelReader reader, Element entityElement, UtilTimer utilTimer, ModelInfo def) {
         super(reader, entityElement, def);
@@ -115,7 +131,7 @@
         }
 
         for (Element viewLinkElement: UtilXml.childElementList(entityElement, "view-link")) {
-            ModelViewLink viewLink = new ModelViewLink(viewLinkElement);
+            ModelViewLink viewLink = new ModelViewLink(this, viewLinkElement);
             this.addViewLink(viewLink);
         }
 
@@ -124,9 +140,7 @@
         
         Element entityConditionElement = UtilXml.firstChildElement(entityElement, "entity-condition");
         if (entityConditionElement != null) {
-            this.byConditionFinder = new ByConditionFinder(entityConditionElement);
-            // make sure the entity name is set since the XML for this particular condition doesn't allow it
-            this.byConditionFinder.setEntityName(this.entityName);
+            this.viewEntityCondition = new ViewEntityCondition(this, null, entityConditionElement);
         }
 
         // before finishing, make sure the table name is null, this should help bring up errors early...
@@ -278,8 +292,19 @@
         this.viewLinks.add(viewLink);
     }
     
-    public ByConditionFinder getByConditionFinder() {
-        return this.byConditionFinder;
+    public EntityCondition getViewEntityConditionWhere(ModelFieldTypeReader modelFieldTypeReader) {
+        if (this.viewEntityCondition == null) return null;
+        EntityCondition viewEntityConditionWhere = this.viewEntityCondition.getWhereCondition(modelFieldTypeReader);
+        return viewEntityConditionWhere;
+    }
+    public EntityCondition getViewEntityConditionHaving(ModelFieldTypeReader modelFieldTypeReader) {
+        if (this.viewEntityCondition == null) return null;
+        EntityCondition viewEntityConditionHaving = this.viewEntityCondition.getHavingCondition(modelFieldTypeReader);
+        return viewEntityConditionHaving;
+    }
+    public List<String> getViewEntityConditionOrderBy() {
+        if (this.viewEntityCondition == null) return null;
+        return this.viewEntityCondition.getOrderByList();
     }
 
     @Override
@@ -957,10 +982,11 @@
         protected String relEntityAlias = "";
         protected boolean relOptional = false;
         protected List<ModelKeyMap> keyMaps = FastList.newInstance();
+        protected ViewEntityCondition viewEntityCondition = null;
 
         protected ModelViewLink() {}
 
-        public ModelViewLink(Element viewLinkElement) {
+        public ModelViewLink(ModelViewEntity modelViewEntity, Element viewLinkElement) {
             this.entityAlias = UtilXml.checkEmpty(viewLinkElement.getAttribute("entity-alias")).intern();
             this.relEntityAlias = UtilXml.checkEmpty(viewLinkElement.getAttribute("rel-entity-alias")).intern();
             // if anything but true will be false; ie defaults to false
@@ -973,6 +999,11 @@
 
                 if (keyMap != null) keyMaps.add(keyMap);
             }
+
+            Element entityConditionElement = UtilXml.firstChildElement(viewLinkElement, "entity-condition");
+            if (entityConditionElement != null) {
+                this.viewEntityCondition = new ViewEntityCondition(modelViewEntity, this, entityConditionElement);
+            }
         }
 
         public ModelViewLink(String entityAlias, String relEntityAlias, Boolean relOptional, ModelKeyMap... keyMaps) {
@@ -1081,4 +1112,198 @@
             }
         }
     }
+    
+    public static class ViewEntityCondition {
+        protected ModelViewEntity modelViewEntity;
+        protected boolean filterByDate;
+        protected boolean distinct;
+        protected List<String> orderByList;
+        protected ViewCondition whereCondition;
+        protected ViewCondition havingCondition;
+
+        public ViewEntityCondition(ModelViewEntity modelViewEntity, ModelViewLink modelViewLink, Element element) {
+            this.modelViewEntity = modelViewEntity;
+            this.filterByDate = "true".equals(element.getAttribute("filter-by-date"));
+            this.distinct = "true".equals(element.getAttribute("distinct"));
+            // process order-by
+            List<? extends Element> orderByElementList = UtilXml.childElementList(element, "order-by");
+            if (orderByElementList.size() > 0) {
+                orderByList = FastList.newInstance();
+                for (Element orderByElement: orderByElementList) {
+                    orderByList.add(orderByElement.getAttribute("field-name"));
+                }
+            }
+            
+            Element conditionExprElement = UtilXml.firstChildElement(element, "condition-expr");
+            Element conditionListElement = UtilXml.firstChildElement(element, "condition-list");
+            if (conditionExprElement != null) {
+                this.whereCondition = new ViewConditionExpr(this, conditionExprElement);
+            } else if (conditionListElement != null) {
+                this.whereCondition = new ViewConditionList(this, conditionListElement);
+            }
+
+            Element havingConditionListElement = UtilXml.firstChildElement(element, "having-condition-list");
+            if (havingConditionListElement != null) {
+                this.havingCondition = new ViewConditionList(this, havingConditionListElement);
+            }
+        }
+        
+        public List<String> getOrderByList() {
+            return this.orderByList;
+        }
+        
+        public EntityCondition getWhereCondition(ModelFieldTypeReader modelFieldTypeReader) {
+            if (this.whereCondition != null) {
+                return this.whereCondition.createCondition(modelFieldTypeReader);
+            } else {
+                return null;
+            }
+        }
+        
+        public EntityCondition getHavingCondition(ModelFieldTypeReader modelFieldTypeReader) {
+            if (this.havingCondition != null) {
+                return this.havingCondition.createCondition(modelFieldTypeReader);
+            } else {
+                return null;
+            }
+        }
+    }
+
+    public static interface ViewCondition extends Serializable {
+        public EntityCondition createCondition(ModelFieldTypeReader modelFieldTypeReader);
+    }
+    public static class ViewConditionExpr implements ViewCondition {
+        protected ViewEntityCondition viewEntityCondition;
+        protected String entityAlias;
+        protected String fieldName;
+        protected String operator;
+        protected String relEntityAlias;
+        protected String relFieldName;
+        protected Object value;
+        protected boolean ignoreCase;
+
+        public ViewConditionExpr(ViewEntityCondition viewEntityCondition, Element conditionExprElement) {
+            this.viewEntityCondition = viewEntityCondition;
+            this.entityAlias = conditionExprElement.getAttribute("entity-alias");
+            this.fieldName = conditionExprElement.getAttribute("field-name");
+
+            this.operator = UtilFormatOut.checkEmpty(conditionExprElement.getAttribute("operator"), "equals");
+            this.relEntityAlias = conditionExprElement.getAttribute("rel-entity-alias");
+            this.relFieldName = conditionExprElement.getAttribute("rel-field-name");
+            this.value = conditionExprElement.getAttribute("value");
+            this.ignoreCase = "true".equals(conditionExprElement.getAttribute("ignore-case"));
+        }
+
+        public EntityCondition createCondition(ModelFieldTypeReader modelFieldTypeReader) {
+            EntityOperator operator = EntityOperator.lookup(this.operator);
+            if (operator == null) {
+                throw new IllegalArgumentException("Could not find an entity operator for the name: " + this.operator);
+            }
+
+            // If IN or BETWEEN operator, see if value is a literal list and split it
+            if ((operator == EntityOperator.IN || operator == EntityOperator.BETWEEN)
+                    && value instanceof String) {
+                String delim = null;
+                if (((String)value).indexOf("|") >= 0) {
+                    delim = "|";
+                } else if (((String)value).indexOf(",") >= 0) {
+                    delim = ",";
+                }
+                if (UtilValidate.isNotEmpty(delim)) {
+                    value = StringUtil.split((String) value, delim);
+                }
+            }
+            
+            if(this.viewEntityCondition.modelViewEntity.getField(fieldName) == null) {
+                throw new IllegalArgumentException("Error in Entity Find: could not find field [" + fieldName + "] in entity with name [" + this.viewEntityCondition.modelViewEntity.getEntityName() + "]");
+            }
+
+            // don't convert the field to the desired type if this is an IN or BETWEEN operator and we have a Collection
+            if (!((operator == EntityOperator.IN || operator == EntityOperator.BETWEEN)
+                    && value instanceof Collection)) {
+                // now to a type conversion for the target fieldName
+                value = this.viewEntityCondition.modelViewEntity.convertFieldValue(this.viewEntityCondition.modelViewEntity.getField(fieldName), value, modelFieldTypeReader, FastMap.<String, Object>newInstance());
+            }
+
+            if (Debug.verboseOn()) Debug.logVerbose("Got value for fieldName [" + fieldName + "]: " + value, module);
+            
+            Object lhs = EntityFieldValue.makeFieldValue(fieldName, entityAlias, this.viewEntityCondition.modelViewEntity);
+            Object rhs = null;
+            if (value != null) {
+                rhs = value;
+            } else {
+                rhs = EntityFieldValue.makeFieldValue(relFieldName, relEntityAlias, this.viewEntityCondition.modelViewEntity);
+            }
+            
+            if (operator == EntityOperator.NOT_EQUAL && value != null) {
+                // since some databases don't consider nulls in != comparisons, explicitly include them
+                // this makes more sense logically, but if anyone ever needs it to not behave this way we should add an "or-null" attribute that is true by default
+                if (ignoreCase) {
+                    return EntityCondition.makeCondition(
+                            EntityCondition.makeCondition(EntityFunction.UPPER(lhs), (EntityComparisonOperator) operator, EntityFunction.UPPER(rhs)),
+                            EntityOperator.OR,
+                            EntityCondition.makeCondition(lhs, EntityOperator.EQUALS, null));
+                } else {
+                    return EntityCondition.makeCondition(
+                            EntityCondition.makeCondition(lhs, (EntityComparisonOperator) operator, rhs),
+                            EntityOperator.OR,
+                            EntityCondition.makeCondition(lhs, EntityOperator.EQUALS, null));
+                }
+            } else {
+                if (ignoreCase) {
+                    // use the stuff to upper case both sides
+                    return EntityCondition.makeCondition(EntityFunction.UPPER(lhs), (EntityComparisonOperator) operator, EntityFunction.UPPER(rhs));
+                } else {
+                    return EntityCondition.makeCondition(lhs, (EntityComparisonOperator) operator, rhs);
+                }
+            }
+        }
+    }
+
+    public static class ViewConditionList implements ViewCondition {
+        protected ViewEntityCondition viewEntityCondition;
+        List<ViewCondition> conditionList = new LinkedList<ViewCondition>();
+        String combine;
+
+        public ViewConditionList(ViewEntityCondition viewEntityCondition, Element conditionListElement) {
+            this.viewEntityCondition = viewEntityCondition;
+            this.combine = conditionListElement.getAttribute("combine");
+
+            List<? extends Element> subElements = UtilXml.childElementList(conditionListElement);
+            for (Element subElement: subElements) {
+                if ("condition-expr".equals(subElement.getNodeName())) {
+                    conditionList.add(new ViewConditionExpr(this.viewEntityCondition, subElement));
+                } else if ("condition-list".equals(subElement.getNodeName())) {
+                    conditionList.add(new ViewConditionList(this.viewEntityCondition, subElement));
+                } else {
+                    throw new IllegalArgumentException("Invalid element with name [" + subElement.getNodeName() + "] found under a condition-list element.");
+                }
+            }
+        }
+
+        public EntityCondition createCondition(ModelFieldTypeReader modelFieldTypeReader) {
+            if (this.conditionList.size() == 0) {
+                return null;
+            }
+            if (this.conditionList.size() == 1) {
+                ViewCondition condition = this.conditionList.get(0);
+                return condition.createCondition(modelFieldTypeReader);
+            }
+
+            List<EntityCondition> entityConditionList = FastList.<EntityCondition>newInstance();
+            for (ViewCondition curCondition: conditionList) {
+                EntityCondition econd = curCondition.createCondition(modelFieldTypeReader);
+                if (econd != null) {
+                    entityConditionList.add(econd);
+                }
+            }
+
+            EntityOperator operator = EntityOperator.lookup(this.combine);
+            if (operator == null) {
+                throw new IllegalArgumentException("Could not find an entity operator for the name: " + operator);
+            }
+
+            return EntityCondition.makeCondition(entityConditionList, (EntityJoinOperator) operator);
+        }
+    }
 }