svn commit: r805519 [7/9] - in /ofbiz/branches/executioncontext20090812: ./ applications/accounting/config/ applications/accounting/data/ applications/accounting/data/helpdata/ applications/accounting/script/org/ofbiz/accounting/finaccount/ application...

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

svn commit: r805519 [7/9] - in /ofbiz/branches/executioncontext20090812: ./ applications/accounting/config/ applications/accounting/data/ applications/accounting/data/helpdata/ applications/accounting/script/org/ofbiz/accounting/finaccount/ application...

adrianc
Modified: ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelViewEntity.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelViewEntity.java?rev=805519&r1=805518&r2=805519&view=diff
==============================================================================
--- ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelViewEntity.java (original)
+++ ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/model/ModelViewEntity.java Tue Aug 18 18:10:44 2009
@@ -1,165 +1,1337 @@
+/*******************************************************************************
+ * 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.ofbiz.entity.model;
 
 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;
 
-import org.ofbiz.entity.condition.EntityCondition;
-
-public interface ModelViewEntity extends ModelEntity {
-
-    public interface ComplexAliasMember {
-        public void makeAliasColName(StringBuilder colNameBuffer, StringBuilder fieldTypeBuffer, ModelViewEntity modelViewEntity, ModelReader modelReader);
-    }
+import javolution.util.FastList;
+import javolution.util.FastMap;
 
-    public interface ComplexAlias extends ComplexAliasMember {
-        public void addComplexAliasMember(ComplexAliasMember complexAliasMember);
+import org.ofbiz.base.util.Debug;
+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.entity.condition.EntityComparisonOperator;
+import org.ofbiz.entity.condition.EntityCondition;
+import org.ofbiz.entity.condition.EntityConditionValue;
+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.jdbc.SqlJdbcUtil;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+/**
+ * This class extends ModelEntity and provides additional information appropriate to view entities
+ */
+@SuppressWarnings("serial")
+public class ModelViewEntity extends ModelEntity {
+    public static final String module = ModelViewEntity.class.getName();
+
+    public static Map<String, String> functionPrefixMap = FastMap.newInstance();
+    static {
+        functionPrefixMap.put("min", "MIN(");
+        functionPrefixMap.put("max", "MAX(");
+        functionPrefixMap.put("sum", "SUM(");
+        functionPrefixMap.put("avg", "AVG(");
+        functionPrefixMap.put("count", "COUNT(");
+        functionPrefixMap.put("count-distinct", "COUNT(DISTINCT ");
+        functionPrefixMap.put("upper", "UPPER(");
+        functionPrefixMap.put("lower", "LOWER(");
     }
 
-    public interface ModelAlias {
+    /** Contains member-entity alias name definitions: key is alias, value is ModelMemberEntity */
+    protected Map<String, ModelMemberEntity> memberModelMemberEntities = FastMap.newInstance();
 
-        public String getColAlias();
+    /** A list of all ModelMemberEntity entries; this is mainly used to preserve the original order of member entities from the XML file */
+    protected List<ModelMemberEntity> allModelMemberEntities = FastList.newInstance();
 
-        public String getDescription();
+    /** Contains member-entity ModelEntities: key is alias, value is ModelEntity; populated with fields */
+    protected Map<String, ModelEntity> memberModelEntities = null;
 
-        public String getEntityAlias();
+    /** List of alias-alls which act as a shortcut for easily pulling over member entity fields */
+    protected List<ModelAliasAll> aliasAlls = FastList.newInstance();
 
-        public String getField();
+    /** List of aliases with information in addition to what is in the standard field list */
+    protected List<ModelAlias> aliases = FastList.newInstance();
 
-        public String getFunction();
+    /** List of view links to define how entities are connected (or "joined") */
+    protected List<ModelViewLink> viewLinks = FastList.newInstance();
 
-        public boolean getGroupBy();
+    /** A List of the Field objects for the View Entity, one for each GROUP BY field */
+    protected List<ModelField> groupBys = FastList.newInstance();
 
-        public boolean getIsFromAliasAll();
+    protected Map<String, Map<String, ModelConversion>> conversions = FastMap.newInstance();
+    
+    protected ViewEntityCondition viewEntityCondition = null;
 
-        public Boolean getIsPk();
+    public ModelViewEntity(ModelReader reader, Element entityElement, UtilTimer utilTimer, ModelInfo def) {
+        super(reader, entityElement, def);
 
-        public String getName();
+        if (utilTimer != null) utilTimer.timerString("  createModelViewEntity: before general/basic info");
+        this.populateBasicInfo(entityElement);
 
-        public boolean isComplexAlias();
+        if (utilTimer != null) utilTimer.timerString("  createModelViewEntity: before \"member-entity\"s");
+        for (Element memberEntityElement: UtilXml.childElementList(entityElement, "member-entity")) {
+            String alias = UtilXml.checkEmpty(memberEntityElement.getAttribute("entity-alias")).intern();
+            String name = UtilXml.checkEmpty(memberEntityElement.getAttribute("entity-name")).intern();
+            if (name.length() <= 0 || alias.length() <= 0) {
+                Debug.logError("[new ModelViewEntity] entity-alias or entity-name missing on member-entity element of the view-entity " + this.entityName, module);
+            } else {
+                ModelMemberEntity modelMemberEntity = new ModelMemberEntity(alias, name);
+                this.addMemberModelMemberEntity(modelMemberEntity);
+            }
+        }
+
+        // when reading aliases and alias-alls, just read them into the alias list, there will be a pass
+        // after loading all entities to go back and fill in all of the ModelField entries
+        for (Element aliasElement: UtilXml.childElementList(entityElement, "alias-all")) {
+            ModelViewEntity.ModelAliasAll aliasAll = new ModelAliasAll(aliasElement);
+            this.aliasAlls.add(aliasAll);
+        }
+
+        if (utilTimer != null) utilTimer.timerString("  createModelViewEntity: before aliases");
+        for (Element aliasElement: UtilXml.childElementList(entityElement, "alias")) {
+            ModelViewEntity.ModelAlias alias = new ModelAlias(aliasElement);
+            this.aliases.add(alias);
+        }
+
+        for (Element viewLinkElement: UtilXml.childElementList(entityElement, "view-link")) {
+            ModelViewLink viewLink = new ModelViewLink(this, viewLinkElement);
+            this.addViewLink(viewLink);
+        }
 
-        public void makeAliasColName(StringBuilder colNameBuffer, StringBuilder fieldTypeBuffer, ModelViewEntity modelViewEntity, ModelReader modelReader);
-
-        public void setComplexAliasMember(ComplexAliasMember complexAliasMember);
+        if (utilTimer != null) utilTimer.timerString("  createModelEntity: before relations");
+        this.populateRelated(reader, entityElement);
+        
+        Element entityConditionElement = UtilXml.firstChildElement(entityElement, "entity-condition");
+        if (entityConditionElement != null) {
+            this.viewEntityCondition = new ViewEntityCondition(this, null, entityConditionElement);
+        }
 
-        public void setDescription(String description);
+        // before finishing, make sure the table name is null, this should help bring up errors early...
+        this.tableName = null;
     }
 
-    public interface ModelAliasAll {
-
-        public String getEntityAlias();
+    public ModelViewEntity(DynamicViewEntity dynamicViewEntity, ModelReader modelReader) {
+        this.entityName = dynamicViewEntity.getEntityName();
+        this.packageName = dynamicViewEntity.getPackageName();
+        this.title = dynamicViewEntity.getTitle();
+        this.defaultResourceName = dynamicViewEntity.getDefaultResourceName();
+
+        // member-entities
+        Iterator<Map.Entry<String, ModelMemberEntity>> modelMemberEntitiesEntryIter = dynamicViewEntity.getModelMemberEntitiesEntryIter();
+        while (modelMemberEntitiesEntryIter.hasNext()) {
+            Map.Entry<String, ModelMemberEntity> entry = modelMemberEntitiesEntryIter.next();
+            this.addMemberModelMemberEntity(entry.getValue());
+        }
+
+        // alias-alls
+        dynamicViewEntity.addAllAliasAllsToList(this.aliasAlls);
+
+        // aliases
+        dynamicViewEntity.addAllAliasesToList(this.aliases);
+
+        // view-links
+        dynamicViewEntity.addAllViewLinksToList(this.viewLinks);
+
+        // relations
+        dynamicViewEntity.addAllRelationsToList(this.relations);
+
+        // finalize stuff
+        // note that this doesn't result in a call to populateReverseLinks because a DynamicViewEntity should never be cached anyway, and will blow up when attempting to make the reverse links to the DynamicViewEntity
+        this.populateFieldsBasic(modelReader);
+    }
 
-        public String getFunction();
+    public Map<String, ModelMemberEntity> getMemberModelMemberEntities() {
+        return this.memberModelMemberEntities;
+    }
 
-        public boolean getGroupBy();
+    public List<ModelMemberEntity> getAllModelMemberEntities() {
+        return this.allModelMemberEntities;
+    }
 
-        public String getPrefix();
+    public ModelMemberEntity getMemberModelMemberEntity(String alias) {
+        return this.memberModelMemberEntities.get(alias);
+    }
 
-        public boolean shouldExclude(String fieldName);
+    public ModelEntity getMemberModelEntity(String alias) {
+        if (this.memberModelEntities == null) {
+            this.memberModelEntities = FastMap.newInstance();
+            populateFields(this.getModelReader());
+        }
+        return this.memberModelEntities.get(alias);
     }
 
-    public interface ModelConversion {
-        public void addAllAliasConversions(List<String> aliases, String fieldName);
+    public void addMemberModelMemberEntity(ModelMemberEntity modelMemberEntity) {
+        this.memberModelMemberEntities.put(modelMemberEntity.getEntityAlias(), modelMemberEntity);
+        this.allModelMemberEntities.add(modelMemberEntity);
+    }
 
-        public void addAllAliasConversions(String fieldName, String... aliases);
+    public void removeMemberModelMemberEntity(String alias) {
+        ModelMemberEntity modelMemberEntity = this.memberModelMemberEntities.remove(alias);
 
-        public void addConversion(String fromFieldName, String toFieldName);
+        if (modelMemberEntity == null) return;
+        this.allModelMemberEntities.remove(modelMemberEntity);
+    }
 
-        public Map<String, Object> convert(Map<String, Object> values);
+    /** The col-name of the Field, the alias of the field if this is on a view-entity */
+    @Override
+    public String getColNameOrAlias(String fieldName) {
+        ModelField modelField = this.getField(fieldName);
+        String fieldString = modelField.getColName();
+        ModelViewEntity.ModelAlias alias = getAlias(fieldName);
+        if (alias != null) {
+            fieldString = alias.getColAlias();
+        }
+        return fieldString;
     }
 
-    public interface ModelMemberEntity {
-        public String getEntityAlias();
+    /** List of aliases with information in addition to what is in the standard field list */
+    public ModelAlias getAlias(int index) {
+        return this.aliases.get(index);
+    }
 
-        public String getEntityName();
+    public ModelAlias getAlias(String name) {
+        Iterator<ModelAlias> aliasIter = getAliasesIterator();
+        while (aliasIter.hasNext()) {
+            ModelAlias alias = aliasIter.next();
+            if (alias.name.equals(name)) {
+                return alias;
+            }
+        }
+        return null;
     }
 
-    public interface ModelViewLink {
+    public int getAliasesSize() {
+        return this.aliases.size();
+    }
 
-        public String getEntityAlias();
+    public Iterator<ModelAlias> getAliasesIterator() {
+        return this.aliases.iterator();
+    }
 
-        public ModelKeyMap getKeyMap(int index);
+    public List<ModelAlias> getAliasesCopy() {
+        List<ModelAlias> newList = FastList.newInstance();
+        newList.addAll(this.aliases);
+        return newList;
+    }
 
-        public List<ModelKeyMap> getKeyMapsCopy();
+    public List<ModelField> getGroupBysCopy() {
+        return getGroupBysCopy(null);
+    }
 
-        public Iterator<ModelKeyMap> getKeyMapsIterator();
+    public List<ModelField> getGroupBysCopy(List<ModelField> selectFields) {
+        List<ModelField> newList = FastList.newInstance();
+        if (UtilValidate.isEmpty(selectFields)) {
+            newList.addAll(this.groupBys);
+        } else {
+            for (ModelField groupByField: this.groupBys) {
+                if (selectFields.contains(groupByField)) {
+                    newList.add(groupByField);
+                }
+            }
+        }
+        return newList;
+    }
 
-        public int getKeyMapsSize();
+    /** List of view links to define how entities are connected (or "joined") */
+    public ModelViewLink getViewLink(int index) {
+        return this.viewLinks.get(index);
+    }
 
-        public String getRelEntityAlias();
+    public int getViewLinksSize() {
+        return this.viewLinks.size();
+    }
 
-        public boolean isRelOptional();
+    public Iterator<ModelViewLink> getViewLinksIterator() {
+        return this.viewLinks.iterator();
     }
 
-    public static interface ViewCondition extends Serializable {
-        public EntityCondition createCondition(ModelFieldTypeReader modelFieldTypeReader, List<String> entityAliasStack);
+    public List<ModelViewLink> getViewLinksCopy() {
+        List<ModelViewLink> newList = FastList.newInstance();
+        newList.addAll(this.viewLinks);
+        return newList;
     }
 
-    public interface ViewEntityCondition {
-        public EntityCondition getHavingCondition(ModelFieldTypeReader modelFieldTypeReader, List<String> entityAliasStack);
+    public void addViewLink(ModelViewLink viewLink) {
+        this.viewLinks.add(viewLink);
+    }
+    
+    public void populateViewEntityConditionInformation(ModelFieldTypeReader modelFieldTypeReader, List<EntityCondition> whereConditions, List<EntityCondition> havingConditions, List<String> orderByList, List<String> entityAliasStack) {
+        if (entityAliasStack == null) {
+            entityAliasStack = FastList.newInstance();
+        }
+        
+        if (this.viewEntityCondition != null) {
+            EntityCondition whereCondition = this.viewEntityCondition.getWhereCondition(modelFieldTypeReader, entityAliasStack);
+            if (whereCondition != null) {
+                whereConditions.add(whereCondition);
+            }
+        }
         
-        public List<String> getOrderByList();
+        if (this.viewEntityCondition != null) {
+            EntityCondition havingCondition = this.viewEntityCondition.getHavingCondition(modelFieldTypeReader, entityAliasStack);
+            if (havingCondition != null) {
+                havingConditions.add(havingCondition);
+            }
+        }
         
-        public EntityCondition getWhereCondition(ModelFieldTypeReader modelFieldTypeReader, List<String> entityAliasStack);
+        // add the current one first so it overrides the lower level ones
+        if (this.viewEntityCondition != null) {
+            List<String> currentOrderByList = this.viewEntityCondition.getOrderByList();
+            if (currentOrderByList != null) {
+                orderByList.addAll(currentOrderByList);
+            }
+        }
+        
+        for (Map.Entry<String, ModelEntity> memberEntityEntry: this.memberModelEntities.entrySet()) {
+            if (memberEntityEntry.getValue() instanceof ModelViewEntity) {
+                ModelViewEntity memberViewEntity = (ModelViewEntity) memberEntityEntry.getValue();
+                entityAliasStack.add(memberEntityEntry.getKey());
+                memberViewEntity.populateViewEntityConditionInformation(modelFieldTypeReader, whereConditions, havingConditions, orderByList, entityAliasStack);
+                entityAliasStack.remove(entityAliasStack.size() - 1);
+            }
+        }
     }
 
-    public void addMemberModelMemberEntity(ModelMemberEntity modelMemberEntity);
-
-    public void addViewLink(ModelViewLink viewLink);
+    @Override
+    public String colNameString(String separator, String afterLast, boolean alias, ModelField... flds) {
+        return colNameString(Arrays.asList(flds), separator, afterLast, alias);
+    }
 
-    public List<Map<String, Object>> convert(String fromEntityName, Map<String, Object> data);
+    @Override
+    public String colNameString(List<ModelField> flds, String separator, String afterLast, boolean alias) {
+        StringBuilder returnString = new StringBuilder();
+
+        if (flds.size() < 1) {
+            return "";
+        }
+
+        Iterator<ModelField> fldsIt = flds.iterator();
+        while (fldsIt.hasNext()) {
+            ModelField field = fldsIt.next();
+            returnString.append(field.colName);
+            if (alias) {
+                ModelAlias modelAlias = this.getAlias(field.name);
+                if (modelAlias != null) {
+                    returnString.append(" AS " + modelAlias.getColAlias());
+                }
+            }
+            if (fldsIt.hasNext()) {
+                returnString.append(separator);
+            }
+        }
 
-    /** List of aliases with information in addition to what is in the standard field list */
-    public ModelAlias getAlias(int index);
+        returnString.append(afterLast);
+        return returnString.toString();
+    }
 
-    public ModelAlias getAlias(String name);
+    protected ModelEntity aliasedModelEntity = new ModelEntity();
 
-    public ModelEntity getAliasedEntity(String entityAlias, ModelReader modelReader);
+    public ModelEntity getAliasedModelEntity() {
+        return this.aliasedModelEntity;
+    }
 
-    public ModelField getAliasedField(ModelEntity aliasedEntity, String field, ModelReader modelReader);
+    public ModelEntity getAliasedEntity(String entityAlias, ModelReader modelReader) {
+        ModelMemberEntity modelMemberEntity = this.memberModelMemberEntities.get(entityAlias);
+        if (modelMemberEntity == null) {
+            Debug.logError("No member entity with alias " + entityAlias + " found in view-entity " + this.getEntityName() + "; this view-entity will NOT be usable...", module);
+            return null;
+        }
+
+        String aliasedEntityName = modelMemberEntity.getEntityName();
+        ModelEntity aliasedEntity = modelReader.getModelEntityNoCheck(aliasedEntityName);
+        if (aliasedEntity == null) {
+            Debug.logError("[ModelViewEntity.populateFields] ERROR: could not find ModelEntity for entity name: " + aliasedEntityName, module);
+            return null;
+        }
 
-    public ModelEntity getAliasedModelEntity();
+        return aliasedEntity;
+    }
 
-    public List<ModelAlias> getAliasesCopy();
+    public ModelField getAliasedField(ModelEntity aliasedEntity, String field, ModelReader modelReader) {
+        ModelField aliasedField = aliasedEntity.getField(field);
+        if (aliasedField == null) {
+            Debug.logError("[ModelViewEntity.populateFields] ERROR: could not find ModelField for entity name: " + aliasedEntity.getEntityName() + " and field: " + field, module);
+            return null;
+        }
+        return aliasedField;
+    }
 
-    public Iterator<ModelAlias> getAliasesIterator();
+    public void populateFields(ModelReader modelReader) {
+        populateFieldsBasic(modelReader);
+        populateReverseLinks();
+    }
 
-    public int getAliasesSize();
+    public void populateFieldsBasic(ModelReader modelReader) {
+        if (this.memberModelEntities == null) {
+            this.memberModelEntities = FastMap.newInstance();
+        }
+
+        for (Map.Entry<String, ModelMemberEntity> entry: memberModelMemberEntities.entrySet()) {
+
+            ModelMemberEntity modelMemberEntity = entry.getValue();
+            String aliasedEntityName = modelMemberEntity.getEntityName();
+            ModelEntity aliasedEntity = modelReader.getModelEntityNoCheck(aliasedEntityName);
+            if (aliasedEntity == null) {
+                continue;
+            }
+            memberModelEntities.put(entry.getKey(), aliasedEntity);
+            Iterator<ModelField> aliasedFieldIterator = aliasedEntity.getFieldsIterator();
+            while (aliasedFieldIterator.hasNext()) {
+                ModelField aliasedModelField = aliasedFieldIterator.next();
+                ModelField newModelField = new ModelField();
+                for (int i = 0; i < aliasedModelField.getValidatorsSize(); i++) {
+                    newModelField.addValidator(aliasedModelField.getValidator(i));
+                }
+                newModelField.setColName(modelMemberEntity.getEntityAlias() + "." + aliasedModelField.getColName());
+                newModelField.setName(modelMemberEntity.getEntityAlias() + "." + aliasedModelField.getName());
+                newModelField.setType(aliasedModelField.getType());
+                newModelField.setDescription(aliasedModelField.getDescription());
+                newModelField.setIsPk(false);
+                aliasedModelEntity.addField(newModelField);
+            }
+        }
+
+        expandAllAliasAlls(modelReader);
+
+        for (ModelAlias alias: aliases) {
+            ModelField field = new ModelField();
+            field.setModelEntity(this);
+            field.name = alias.name;
+            field.description = alias.description;
+
+            // if this is a groupBy field, add it to the groupBys list
+            if (alias.groupBy) {
+                this.groupBys.add(field);
+            }
+
+            // show a warning if function is specified and groupBy is true
+            if (UtilValidate.isNotEmpty(alias.function) && alias.groupBy) {
+                Debug.logWarning("The view-entity alias with name=" + alias.name + " has a function value and is specified as a group-by field; this may be an error, but is not necessarily.", module);
+            }
+
+            if (alias.isComplexAlias()) {
+                // if this is a complex alias, make a complex column name...
+                StringBuilder colNameBuffer = new StringBuilder();
+                StringBuilder fieldTypeBuffer = new StringBuilder();
+                alias.makeAliasColName(colNameBuffer, fieldTypeBuffer, this, modelReader);
+                field.colName = colNameBuffer.toString();
+                field.type = fieldTypeBuffer.toString();
+                field.isPk = false;
+            } else {
+                ModelEntity aliasedEntity = getAliasedEntity(alias.entityAlias, modelReader);
+                ModelField aliasedField = getAliasedField(aliasedEntity, alias.field, modelReader);
+                if (aliasedField == null) {
+                    Debug.logError("[ModelViewEntity.populateFields (" + this.getEntityName() + ")] ERROR: could not find ModelField for field name \"" +
+                        alias.field + "\" on entity with name: " + aliasedEntity.getEntityName(), module);
+                    continue;
+                }
+
+                if (alias.isPk != null) {
+                    field.isPk = alias.isPk.booleanValue();
+                } else {
+                    field.isPk = aliasedField.isPk;
+                }
+
+                field.encrypt = aliasedField.encrypt;
+
+                field.type = aliasedField.type;
+                field.validators = aliasedField.validators;
+
+                field.colName = alias.entityAlias + "." + SqlJdbcUtil.filterColName(aliasedField.colName);
+                if (UtilValidate.isEmpty(field.description)) {
+                    field.description = aliasedField.description;
+                }
+            }
+
+            this.fields.add(field);
+            if (field.isPk) {
+                this.pks.add(field);
+            } else {
+                this.nopks.add(field);
+            }
+
+            if ("count".equals(alias.function) || "count-distinct".equals(alias.function)) {
+                // if we have a "count" function we have to change the type
+                field.type = "numeric";
+            }
+
+            if (UtilValidate.isNotEmpty(alias.function)) {
+                String prefix = functionPrefixMap.get(alias.function);
+                if (prefix == null) {
+                    Debug.logWarning("Specified alias function [" + alias.function + "] not valid; must be: min, max, sum, avg, count or count-distinct; using a column name with no function function", module);
+                } else {
+                    field.colName = prefix + field.colName + ")";
+                }
+            }
+        }
+    }
 
-    public List<ModelMemberEntity> getAllModelMemberEntities();
+    protected ModelConversion getOrCreateModelConversion(String aliasName) {
+        ModelEntity member = getMemberModelEntity(aliasName);
+        if (member == null) {
+            String errMsg = "No member found for aliasName - " + aliasName;
+            Debug.logWarning(errMsg, module);
+            throw new RuntimeException("Cannot create View Entity: " + errMsg);
+        }
+
+        Map<String, ModelConversion> aliasConversions = conversions.get(member.getEntityName());
+        if (aliasConversions == null) {
+            aliasConversions = FastMap.newInstance();
+            conversions.put(member.getEntityName(), aliasConversions);
+        }
+        ModelConversion conversion = aliasConversions.get(aliasName);
+        if (conversion == null) {
+            conversion = new ModelConversion(aliasName, member);
+            aliasConversions.put(aliasName, conversion);
+        }
+        return conversion;
+    }
 
-    /** The col-name of the Field, the alias of the field if this is on a view-entity */
-    public String getColNameOrAlias(String fieldName);
+    public void populateReverseLinks() {
+        Map<String, List<String>> containedModelFields = FastMap.newInstance();
+        Iterator<ModelAlias> it = getAliasesIterator();
+        while (it.hasNext()) {
+            ModelViewEntity.ModelAlias alias = it.next();
+            if (alias.isComplexAlias()) {
+                // TODO: conversion for complex-alias needs to be implemented for cache and in-memory eval stuff to work correctly
+                Debug.logWarning("Conversion for complex-alias needs to be implemented for cache and in-memory eval stuff to work correctly, will not work for alias: " + alias.getName() + " of view-entity " + this.getEntityName(), module);
+            } else {
+                ModelConversion conversion = getOrCreateModelConversion(alias.getEntityAlias());
+                conversion.addConversion(alias.getField(), alias.getName());
+            }
+
+            List<String> aliases = containedModelFields.get(alias.getField());
+            if (aliases == null) {
+                aliases = FastList.newInstance();
+                containedModelFields.put(alias.getField(), aliases);
+            }
+            aliases.add(alias.getName());
+        }
+
+        Iterator<ModelViewLink> it2 = getViewLinksIterator();
+        while (it2.hasNext()) {
+            ModelViewEntity.ModelViewLink link = it2.next();
+
+            String leftAlias = link.getEntityAlias();
+            String rightAlias = link.getRelEntityAlias();
+            ModelConversion leftConversion = getOrCreateModelConversion(leftAlias);
+            ModelConversion rightConversion = getOrCreateModelConversion(rightAlias);
+            Iterator<ModelKeyMap> it3 = link.getKeyMapsIterator();
+            Debug.logVerbose(leftAlias + "<->" + rightAlias, module);
+            while (it3.hasNext()) {
+                ModelKeyMap mkm = it3.next();
+                String leftFieldName = mkm.getFieldName();
+                String rightFieldName = mkm.getRelFieldName();
+                rightConversion.addAllAliasConversions(containedModelFields.get(leftFieldName), rightFieldName);
+                leftConversion.addAllAliasConversions(containedModelFields.get(rightFieldName), leftFieldName);
+            }
+        }
+        int[] currentIndex = new int[conversions.size()];
+        int[] maxIndex = new int[conversions.size()];
+        ModelConversion[][] allConversions = new ModelConversion[conversions.size()][];
+        int i = 0;
+        for (Map<String, ModelConversion> aliasConversions: conversions.values()) {
+            currentIndex[i] = 0;
+            maxIndex[i] = aliasConversions.size();
+            allConversions[i] = new ModelConversion[aliasConversions.size()];
+            int j = 0;
+            for (ModelConversion conversion: aliasConversions.values()) {
+                allConversions[i][j] = conversion;
+                j++;
+            }
+            i++;
+        }
+        int ptr = 0;
+        ModelConversion[] currentConversions = new ModelConversion[conversions.size()];
+        for (int j = 0, k; j < currentIndex.length; j++) {
+            for (int l = 0; l < maxIndex[ j ]; l++) {
+                while (true) {
+                    for (i = 0, k = 0; i < currentIndex.length; i++) {
+                        if (i == j && currentIndex[i] == l) continue;
+                        currentConversions[k++] = allConversions[i][currentIndex[i]];
+                    }
+                    Debug.logVerbose(j + "," + l + ":" + Arrays.asList(currentConversions), module);
+                    while (ptr < currentIndex.length && ++currentIndex[ptr] == maxIndex[ptr]) {
+                        currentIndex[ptr] = 0;
+                        ptr++;
+                    }
+                    if (ptr == currentIndex.length) break;
+                    ptr = 0;
+                }
+            }
+        }
+        Debug.logVerbose(this + ":" + conversions, module);
+    }
 
-    public List<ModelField> getGroupBysCopy();
+    public List<Map<String, Object>> convert(String fromEntityName, Map<String, Object> data) {
+        Map<String, ModelConversion> conversions = this.conversions.get(fromEntityName);
+        if (conversions == null) return null;
+        List<Map<String, Object>> values = FastList.newInstance();
+        for (ModelConversion conversion: conversions.values()) {
+            values.add(conversion.convert(data));
+        }
+        return values;
+    }
 
-    public List<ModelField> getGroupBysCopy(List<ModelField> selectFields);
+    /**
+     * Go through all aliasAlls and create an alias for each field of each member entity
+     */
+    private void expandAllAliasAlls(ModelReader modelReader) {
+        for (ModelAliasAll aliasAll: aliasAlls) {
+            String prefix = aliasAll.getPrefix();
+            String function = aliasAll.getFunction();
+            boolean groupBy = aliasAll.getGroupBy();
+
+            ModelMemberEntity modelMemberEntity = memberModelMemberEntities.get(aliasAll.getEntityAlias());
+            if (modelMemberEntity == null) {
+                Debug.logError("Member entity referred to in alias-all not found, ignoring: " + aliasAll.getEntityAlias(), module);
+                continue;
+            }
+
+            String aliasedEntityName = modelMemberEntity.getEntityName();
+            ModelEntity aliasedEntity = modelReader.getModelEntityNoCheck(aliasedEntityName);
+            if (aliasedEntity == null) {
+                Debug.logError("Entity referred to in member-entity " + aliasAll.getEntityAlias() + " not found, ignoring: " + aliasedEntityName, module);
+                continue;
+            }
+
+            List<String> entFieldList = aliasedEntity.getAllFieldNames();
+            if (entFieldList == null) {
+                Debug.logError("Entity referred to in member-entity " + aliasAll.getEntityAlias() + " has no fields, ignoring: " + aliasedEntityName, module);
+                continue;
+            }
+
+            for (String fieldName: entFieldList) {
+                // now merge the lists, leaving out any that duplicate an existing alias name
+                String aliasName = fieldName;
+                ModelField modelField = aliasedEntity.getField(fieldName);
+                if (modelField.getIsAutoCreatedInternal()) {
+                    // never auto-alias these
+                    continue;
+                }
+                if (aliasAll.shouldExclude(fieldName)) {
+                    // if specified as excluded, leave it out
+                    continue;
+                }
+
+                if (UtilValidate.isNotEmpty(prefix)) {
+                    StringBuilder newAliasBuffer = new StringBuilder(prefix);
+                    //make sure the first letter is uppercase to delineate the field name
+                    newAliasBuffer.append(Character.toUpperCase(aliasName.charAt(0)));
+                    newAliasBuffer.append(aliasName.substring(1));
+                    aliasName = newAliasBuffer.toString();
+                }
+
+                ModelAlias existingAlias = this.getAlias(aliasName);
+                if (existingAlias != null) {
+                    //log differently if this is part of a view-link key-map because that is a common case when a field will be auto-expanded multiple times
+                    boolean isInViewLink = false;
+                    Iterator<ModelViewLink> viewLinkIter = this.getViewLinksIterator();
+                    while (viewLinkIter.hasNext() && !isInViewLink) {
+                        ModelViewLink modelViewLink = viewLinkIter.next();
+                        boolean isRel = false;
+                        if (modelViewLink.getRelEntityAlias().equals(aliasAll.getEntityAlias())) {
+                            isRel = true;
+                        } else if (!modelViewLink.getEntityAlias().equals(aliasAll.getEntityAlias())) {
+                            // not the rel-entity-alias or the entity-alias, so move along
+                            continue;
+                        }
+                        Iterator<ModelKeyMap> keyMapIter = modelViewLink.getKeyMapsIterator();
+                        while (keyMapIter.hasNext() && !isInViewLink) {
+                            ModelKeyMap modelKeyMap = keyMapIter.next();
+                            if (!isRel && modelKeyMap.getFieldName().equals(fieldName)) {
+                                isInViewLink = true;
+                            } else if (isRel && modelKeyMap.getRelFieldName().equals(fieldName)) {
+                                isInViewLink = true;
+                            }
+                        }
+                    }
+
+                    //already exists, oh well... probably an override, but log just in case
+                    String warnMsg = "Throwing out field alias in view entity " + this.getEntityName() + " because one already exists with the alias name [" + aliasName + "] and field name [" + modelMemberEntity.getEntityAlias() + "(" + aliasedEntity.getEntityName() + ")." + fieldName + "], existing field name is [" + existingAlias.getEntityAlias() + "." + existingAlias.getField() + "]";
+                    if (isInViewLink) {
+                        Debug.logVerbose(warnMsg, module);
+                    } else {
+                        Debug.logInfo(warnMsg, module);
+                    }
+                    continue;
+                }
+
+                ModelAlias expandedAlias = new ModelAlias();
+                expandedAlias.name = aliasName;
+                expandedAlias.field = fieldName;
+                expandedAlias.entityAlias = aliasAll.getEntityAlias();
+                expandedAlias.isFromAliasAll = true;
+                expandedAlias.colAlias = ModelUtil.javaNameToDbName(UtilXml.checkEmpty(expandedAlias.name));
+                expandedAlias.function = function;
+                expandedAlias.groupBy = groupBy;
+                expandedAlias.description = modelField.getDescription();
+
+                aliases.add(expandedAlias);
+            }
+        }
+    }
 
-    public ModelEntity getMemberModelEntity(String alias);
+    @Override
+    public String toString() {
+        return "ModelViewEntity[" + getEntityName() + "]";
+    }
 
-    public Map<String, ModelMemberEntity> getMemberModelMemberEntities();
+    public static class ModelMemberEntity implements Serializable {
+        protected String entityAlias = "";
+        protected String entityName = "";
+
+        public ModelMemberEntity(String entityAlias, String entityName) {
+            this.entityAlias = entityAlias;
+            this.entityName = entityName;
+        }
+
+        public String getEntityAlias() {
+            return this.entityAlias;
+        }
+
+        public String getEntityName() {
+            return this.entityName;
+        }
+    }
 
-    public ModelMemberEntity getMemberModelMemberEntity(String alias);
+    public static class ModelAliasAll implements Serializable {
+        protected String entityAlias = "";
+        protected String prefix = "";
+        protected Set<String> fieldsToExclude = null;
+        protected boolean groupBy = false;
+        // is specified this alias is a calculated value; can be: min, max, sum, avg, count, count-distinct
+        protected String function = null;
+
+        protected ModelAliasAll() {}
+
+        public ModelAliasAll(String entityAlias, String prefix) {
+            this.entityAlias = entityAlias;
+            this.prefix = prefix;
+        }
+
+        public ModelAliasAll(Element aliasAllElement) {
+            this.entityAlias = UtilXml.checkEmpty(aliasAllElement.getAttribute("entity-alias")).intern();
+            this.prefix = UtilXml.checkEmpty(aliasAllElement.getAttribute("prefix")).intern();
+            this.groupBy = "true".equals(UtilXml.checkEmpty(aliasAllElement.getAttribute("group-by")));
+            this.function = UtilXml.checkEmpty(aliasAllElement.getAttribute("function"));
+
+            List<? extends Element> excludes = UtilXml.childElementList(aliasAllElement, "exclude");
+            if (UtilValidate.isNotEmpty(excludes)) {
+                this.fieldsToExclude = new HashSet<String>();
+                for (Element excludeElement: excludes) {
+                    this.fieldsToExclude.add(excludeElement.getAttribute("field").intern());
+                }
+            }
+
+        }
+
+        public String getEntityAlias() {
+            return this.entityAlias;
+        }
+
+        public String getPrefix() {
+            return this.prefix;
+        }
+
+        public boolean getGroupBy() {
+            return this.groupBy;
+        }
+
+        public String getFunction() {
+            return this.function;
+        }
+
+        public boolean shouldExclude(String fieldName) {
+            if (this.fieldsToExclude == null) {
+                return false;
+            } else {
+                return this.fieldsToExclude.contains(fieldName);
+            }
+        }
+    }
 
-    /** List of view links to define how entities are connected (or "joined") */
-    public ModelViewLink getViewLink(int index);
-    
-    public List<ModelViewLink> getViewLinksCopy();
+    public static class ModelAlias implements Serializable {
+        protected String entityAlias = "";
+        protected String name = "";
+        protected String field = "";
+        protected String colAlias = "";
+        // this is a Boolean object for a tri-state: null, true or false
+        protected Boolean isPk = null;
+        protected boolean groupBy = false;
+        // is specified this alias is a calculated value; can be: min, max, sum, avg, count, count-distinct
+        protected String function = null;
+        protected boolean isFromAliasAll = false;
+        protected ComplexAliasMember complexAliasMember = null;
+        // The description for documentation purposes
+        protected String description = "";
+
+        protected ModelAlias() {}
+
+        public ModelAlias(Element aliasElement) {
+            this.entityAlias = UtilXml.checkEmpty(aliasElement.getAttribute("entity-alias")).intern();
+            this.name = UtilXml.checkEmpty(aliasElement.getAttribute("name")).intern();
+            this.field = UtilXml.checkEmpty(aliasElement.getAttribute("field"), this.name).intern();
+            this.colAlias = UtilXml.checkEmpty(aliasElement.getAttribute("col-alias"), ModelUtil.javaNameToDbName(UtilXml.checkEmpty(this.name))).intern();
+            String primKeyValue = UtilXml.checkEmpty(aliasElement.getAttribute("prim-key"));
+
+            if (UtilValidate.isNotEmpty(primKeyValue)) {
+                this.isPk = Boolean.valueOf("true".equals(primKeyValue));
+            } else {
+                this.isPk = null;
+            }
+            this.groupBy = "true".equals(UtilXml.checkEmpty(aliasElement.getAttribute("group-by")));
+            this.function = UtilXml.checkEmpty(aliasElement.getAttribute("function")).intern();
+            this.description = UtilXml.checkEmpty(UtilXml.childElementValue(aliasElement, "description")).intern();
+
+            Element complexAliasElement = UtilXml.firstChildElement(aliasElement, "complex-alias");
+            if (complexAliasElement != null) {
+                complexAliasMember = new ComplexAlias(complexAliasElement);
+            }
+        }
+
+        public ModelAlias(String entityAlias, String name, String field, String colAlias, Boolean isPk, Boolean groupBy, String function) {
+            this.entityAlias = entityAlias;
+            this.name = name;
+            this.field = UtilXml.checkEmpty(field, this.name);
+            this.colAlias = UtilXml.checkEmpty(colAlias, ModelUtil.javaNameToDbName(UtilXml.checkEmpty(this.name)));
+            this.isPk = isPk;
+            if (groupBy != null) {
+                this.groupBy = groupBy.booleanValue();
+            } else {
+                this.groupBy = false;
+            }
+            this.function = function;
+        }
+
+        public void setComplexAliasMember(ComplexAliasMember complexAliasMember) {
+            this.complexAliasMember = complexAliasMember;
+        }
+
+        public boolean isComplexAlias() {
+            return complexAliasMember != null;
+        }
+
+        public void makeAliasColName(StringBuilder colNameBuffer, StringBuilder fieldTypeBuffer, ModelViewEntity modelViewEntity, ModelReader modelReader) {
+            if (complexAliasMember != null) {
+                complexAliasMember.makeAliasColName(colNameBuffer, fieldTypeBuffer, modelViewEntity, modelReader);
+            }
+        }
+
+        public String getEntityAlias() {
+            return this.entityAlias;
+        }
+
+        public String getName() {
+            return this.name;
+        }
+
+        public String getColAlias() {
+            return this.colAlias;
+        }
+
+        public String getField() {
+            return this.field;
+        }
+
+        public Boolean getIsPk() {
+            return this.isPk;
+        }
+
+        public boolean getGroupBy() {
+            return this.groupBy;
+        }
+
+        public String getFunction() {
+            return this.function;
+        }
+
+        public String getDescription() {
+            return this.description;
+        }
+
+        public void setDescription(String description) {
+            this.description = description;
+        }
+
+        public boolean getIsFromAliasAll() {
+            return this.isFromAliasAll;
+        }
+    }
 
+    public static interface ComplexAliasMember extends Serializable {
+        public void makeAliasColName(StringBuilder colNameBuffer, StringBuilder fieldTypeBuffer, ModelViewEntity modelViewEntity, ModelReader modelReader);
+    }
 
-    public Iterator<ModelViewLink> getViewLinksIterator();
+    public static class ComplexAlias implements ComplexAliasMember {
+        protected List<ComplexAliasMember> complexAliasMembers = FastList.newInstance();
+        protected String operator;
+
+        public ComplexAlias(String operator) {
+            this.operator = operator;
+        }
+
+        public ComplexAlias(Element complexAliasElement) {
+            this.operator = complexAliasElement.getAttribute("operator").intern();
+            // handle all complex-alias and complex-alias-field sub-elements
+            for (Element subElement: UtilXml.childElementList(complexAliasElement)) {
+                String nodeName = subElement.getNodeName();
+                if ("complex-alias".equals(nodeName)) {
+                    this.addComplexAliasMember(new ComplexAlias(subElement));
+                } else if ("complex-alias-field".equals(nodeName)) {
+                    this.addComplexAliasMember(new ComplexAliasField(subElement));
+                }
+            }
+        }
+
+        public void addComplexAliasMember(ComplexAliasMember complexAliasMember) {
+            this.complexAliasMembers.add(complexAliasMember);
+        }
+
+        public void makeAliasColName(StringBuilder colNameBuffer, StringBuilder fieldTypeBuffer, ModelViewEntity modelViewEntity, ModelReader modelReader) {
+            if (complexAliasMembers.size() == 0) {
+                return;
+            } else if (complexAliasMembers.size() == 1) {
+                ComplexAliasMember complexAliasMember = complexAliasMembers.iterator().next();
+                complexAliasMember.makeAliasColName(colNameBuffer, fieldTypeBuffer, modelViewEntity, modelReader);
+            } else {
+                colNameBuffer.append('(');
+                Iterator<ComplexAliasMember> complexAliasMemberIter = complexAliasMembers.iterator();
+                while (complexAliasMemberIter.hasNext()) {
+                    ComplexAliasMember complexAliasMember = complexAliasMemberIter.next();
+                    complexAliasMember.makeAliasColName(colNameBuffer, fieldTypeBuffer, modelViewEntity, modelReader);
+                    if (complexAliasMemberIter.hasNext()) {
+                        colNameBuffer.append(' ');
+                        colNameBuffer.append(this.operator);
+                        colNameBuffer.append(' ');
+                    }
+                }
+                colNameBuffer.append(')');
+            }
+        }
+    }
 
-    public int getViewLinksSize();
+    public static class ComplexAliasField implements ComplexAliasMember {
+        protected String entityAlias = "";
+        protected String field = "";
+        protected String defaultValue = null;
+        protected String function = null;
+
+        public ComplexAliasField(Element complexAliasFieldElement) {
+            this.entityAlias = complexAliasFieldElement.getAttribute("entity-alias").intern();
+            this.field = complexAliasFieldElement.getAttribute("field").intern();
+            this.defaultValue = complexAliasFieldElement.getAttribute("default-value").intern();
+            this.function = complexAliasFieldElement.getAttribute("function").intern();
+        }
+
+        public ComplexAliasField(String entityAlias, String field, String defaultValue, String function) {
+            this.entityAlias = entityAlias;
+            this.field = field;
+            this.defaultValue = defaultValue;
+            this.function = function;
+        }
+
+        /**
+         * Make the alias as follows: function(coalesce(entityAlias.field, defaultValue))
+         */
+        public void makeAliasColName(StringBuilder colNameBuffer, StringBuilder fieldTypeBuffer, ModelViewEntity modelViewEntity, ModelReader modelReader) {
+            ModelEntity modelEntity = modelViewEntity.getAliasedEntity(entityAlias, modelReader);
+            ModelField modelField = modelViewEntity.getAliasedField(modelEntity, field, modelReader);
+
+            String colName = entityAlias + "." + modelField.getColName();
+
+            if (UtilValidate.isNotEmpty(defaultValue)) {
+                colName = "COALESCE(" + colName + "," + defaultValue + ")";
+            }
+
+            if (UtilValidate.isNotEmpty(function)) {
+                String prefix = functionPrefixMap.get(function);
+                if (prefix == null) {
+                    Debug.logWarning("Specified alias function [" + function + "] not valid; must be: min, max, sum, avg, count or count-distinct; using a column name with no function function", module);
+                } else {
+                    colName = prefix + colName + ")";
+                }
+            }
+
+            colNameBuffer.append(colName);
+
+            //set fieldTypeBuffer if not already set
+            if (fieldTypeBuffer.length() == 0) {
+                fieldTypeBuffer.append(modelField.type);
+            }
+        }
+    }
 
-    public void populateFields(ModelReader modelReader);
+    public static class ModelViewLink implements Serializable {
+        protected String entityAlias = "";
+        protected String relEntityAlias = "";
+        protected boolean relOptional = false;
+        protected List<ModelKeyMap> keyMaps = FastList.newInstance();
+        protected ViewEntityCondition viewEntityCondition = null;
+
+        protected ModelViewLink() {}
+
+        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
+            this.relOptional = "true".equals(viewLinkElement.getAttribute("rel-optional"));
+
+            NodeList keyMapList = viewLinkElement.getElementsByTagName("key-map");
+            for (int j = 0; j < keyMapList.getLength(); j++) {
+                Element keyMapElement = (Element) keyMapList.item(j);
+                ModelKeyMap keyMap = new ModelKeyMap(keyMapElement);
+
+                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) {
+            this(entityAlias, relEntityAlias, relOptional, Arrays.asList(keyMaps));
+        }
+
+        public ModelViewLink(String entityAlias, String relEntityAlias, Boolean relOptional, List<ModelKeyMap> keyMaps) {
+            this.entityAlias = entityAlias;
+            this.relEntityAlias = relEntityAlias;
+            if (relOptional != null) {
+                this.relOptional = relOptional.booleanValue();
+            }
+            this.keyMaps.addAll(keyMaps);
+        }
+
+        public String getEntityAlias() {
+            return this.entityAlias;
+        }
+
+        public String getRelEntityAlias() {
+            return this.relEntityAlias;
+        }
+
+        public boolean isRelOptional() {
+            return this.relOptional;
+        }
+
+        public ModelKeyMap getKeyMap(int index) {
+            return this.keyMaps.get(index);
+        }
+
+        public int getKeyMapsSize() {
+            return this.keyMaps.size();
+        }
+
+        public Iterator<ModelKeyMap> getKeyMapsIterator() {
+            return this.keyMaps.iterator();
+        }
+
+        public List<ModelKeyMap> getKeyMapsCopy() {
+            List<ModelKeyMap> newList = FastList.newInstance();
+            newList.addAll(this.keyMaps);
+            return newList;
+        }
+    }
 
-    public void populateFieldsBasic(ModelReader modelReader);
+    public class ModelConversion implements Serializable {
+        protected String aliasName;
+        protected ModelEntity fromModelEntity;
+        protected Map<String, String> fieldMap = FastMap.newInstance();
+        protected Set<String> wildcards = new HashSet<String>();
+
+        public ModelConversion(String aliasName, ModelEntity fromModelEntity) {
+            this.aliasName = aliasName;
+            this.fromModelEntity = fromModelEntity;
+            Iterator<ModelField> it = getFieldsIterator();
+            while (it.hasNext()) {
+                ModelField field = it.next();
+                wildcards.add(field.getName());
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            return fromModelEntity.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof ModelConversion)) return false;
+            ModelConversion other = (ModelConversion) obj;
+            return fromModelEntity.equals(other.fromModelEntity);
+        }
+
+        public void addConversion(String fromFieldName, String toFieldName) {
+            wildcards.remove(toFieldName);
+            fieldMap.put(fromFieldName, toFieldName);
+        }
+
+        @Override
+        public String toString() {
+            //return fromModelEntity.getEntityName() + ":" + fieldMap + ":" + wildcards;
+            return aliasName + "(" + fromModelEntity.getEntityName() + ")";
+        }
+
+        public Map<String, Object> convert(Map<String, Object> values) {
+            Map<String, Object> newValues = FastMap.newInstance();
+            for (Map.Entry<String, String> entry: fieldMap.entrySet()) {
+                newValues.put(entry.getValue(), values.get(entry.getKey()));
+            }
+            for (String key: wildcards) {
+                newValues.put(key, EntityOperator.WILDCARD);
+            }
+            return newValues;
+        }
+
+        public void addAllAliasConversions(String fieldName, String... aliases) {
+            addAllAliasConversions(Arrays.asList(aliases), fieldName);
+        }
+
+        public void addAllAliasConversions(List<String> aliases, String fieldName) {
+            if (aliases != null) {
+                for (String alias: aliases) {
+                    addConversion(fieldName, alias);
+                }
+            }
+        }
+    }
+    
+    public static class ViewEntityCondition {
+        protected ModelViewEntity modelViewEntity;
+        protected ModelViewLink modelViewLink;
+        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.modelViewLink = modelViewLink;
+            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, List<String> entityAliasStack) {
+            if (this.whereCondition != null) {
+                return this.whereCondition.createCondition(modelFieldTypeReader, entityAliasStack);
+            } else {
+                return null;
+            }
+        }
+        
+        public EntityCondition getHavingCondition(ModelFieldTypeReader modelFieldTypeReader, List<String> entityAliasStack) {
+            if (this.havingCondition != null) {
+                return this.havingCondition.createCondition(modelFieldTypeReader, entityAliasStack);
+            } else {
+                return null;
+            }
+        }
+    }
 
-    public void populateReverseLinks();
+    public static interface ViewCondition extends Serializable {
+        public EntityCondition createCondition(ModelFieldTypeReader modelFieldTypeReader, List<String> entityAliasStack);
+    }
     
-    public void populateViewEntityConditionInformation(ModelFieldTypeReader modelFieldTypeReader, List<EntityCondition> whereConditions, List<EntityCondition> havingConditions, List<String> orderByList, List<String> entityAliasStack);
+    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"));
+            
+            // if we are in a view-link, default to the entity-alias and rel-entity-alias there
+            if (this.viewEntityCondition.modelViewLink != null) {
+                if (UtilValidate.isEmpty(this.entityAlias)) {
+                    this.entityAlias = this.viewEntityCondition.modelViewLink.getEntityAlias();
+                }
+                if (UtilValidate.isEmpty(this.relEntityAlias)) {
+                    this.relEntityAlias = this.viewEntityCondition.modelViewLink.getRelEntityAlias();
+                }
+            }
+        }
+        
+        public EntityCondition createCondition(ModelFieldTypeReader modelFieldTypeReader, List<String> entityAliasStack) {
+            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);
+            
+            EntityConditionValue lhs = EntityFieldValue.makeFieldValue(this.fieldName, this.entityAlias, entityAliasStack, this.viewEntityCondition.modelViewEntity);
+            Object rhs = null;
+            if (value != null) {
+                rhs = value;
+            } else {
+                rhs = EntityFieldValue.makeFieldValue(this.relFieldName, this.relEntityAlias, entityAliasStack, 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 void removeMemberModelMemberEntity(String alias);
+    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, List<String> entityAliasStack) {
+            if (this.conditionList.size() == 0) {
+                return null;
+            }
+            if (this.conditionList.size() == 1) {
+                ViewCondition condition = this.conditionList.get(0);
+                return condition.createCondition(modelFieldTypeReader, entityAliasStack);
+            }
+
+            List<EntityCondition> entityConditionList = FastList.<EntityCondition>newInstance();
+            for (ViewCondition curCondition: conditionList) {
+                EntityCondition econd = curCondition.createCondition(modelFieldTypeReader, entityAliasStack);
+                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);
+        }
+    }
 }

Modified: ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java?rev=805519&r1=805518&r2=805519&view=diff
==============================================================================
--- ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java (original)
+++ ofbiz/branches/executioncontext20090812/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java Tue Aug 18 18:10:44 2009
@@ -29,7 +29,7 @@
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.UtilDateTime;
 import org.ofbiz.base.util.UtilMisc;
-import org.ofbiz.entity.EntityFactory;
+import org.ofbiz.entity.GenericEntity;
 import org.ofbiz.entity.GenericEntityException;
 import org.ofbiz.entity.GenericPK;
 import org.ofbiz.entity.GenericValue;
@@ -113,7 +113,7 @@
     public void testCreateTree() throws Exception {
         try {
         // get how many child nodes did we have before creating the tree
-        EntityCondition isChild = EntityCondition.makeCondition("primaryParentNodeId", EntityOperator.NOT_EQUAL, EntityFactory.NULL_FIELD);
+        EntityCondition isChild = EntityCondition.makeCondition("primaryParentNodeId", EntityOperator.NOT_EQUAL, GenericEntity.NULL_FIELD);
         long alreadyStored = delegator.findCountByCondition("TestingNode", isChild, null, null);
 
         //
@@ -123,7 +123,7 @@
         // create the root
         GenericValue root = delegator.create("TestingNode",
                         "testingNodeId", delegator.getNextSeqId("TestingNode"),
-                        "primaryParentNodeId", EntityFactory.NULL_FIELD,
+                        "primaryParentNodeId", GenericEntity.NULL_FIELD,
                         "description", "root");
         int level1;
         for(level1 = 0; level1 < _level1max; level1++) {
@@ -148,7 +148,7 @@
      */
     public void testAddMembersToTree() throws Exception {
         // get the level1 nodes
-        EntityCondition isLevel1 = EntityCondition.makeCondition("primaryParentNodeId", EntityOperator.NOT_EQUAL, EntityFactory.NULL_FIELD);
+        EntityCondition isLevel1 = EntityCondition.makeCondition("primaryParentNodeId", EntityOperator.NOT_EQUAL, GenericEntity.NULL_FIELD);
         List<GenericValue> nodeLevel1 = delegator.findList("TestingNode", isLevel1, null, null, null, false);
 
         List<GenericValue> newValues = new LinkedList<GenericValue>();
@@ -184,7 +184,7 @@
      * Tests findByCondition and tests searching on a view-entity
      */
     public void testCountViews() throws Exception {
-        EntityCondition isNodeWithMember = EntityCondition.makeCondition("testingId", EntityOperator.NOT_EQUAL, EntityFactory.NULL_FIELD);
+        EntityCondition isNodeWithMember = EntityCondition.makeCondition("testingId", EntityOperator.NOT_EQUAL, GenericEntity.NULL_FIELD);
         List<GenericValue> nodeWithMembers = delegator.findList("TestingNodeAndMember", isNodeWithMember, null, null, null, false);
 
         for (GenericValue v: nodeWithMembers) {
@@ -331,7 +331,7 @@
         // Find all the root nodes,
         // delete them their primary key
         //
-        EntityCondition isRoot = EntityCondition.makeCondition("primaryParentNodeId", EntityOperator.EQUALS, EntityFactory.NULL_FIELD);
+        EntityCondition isRoot = EntityCondition.makeCondition("primaryParentNodeId", EntityOperator.EQUALS, GenericEntity.NULL_FIELD);
         List<GenericValue> rootValues = delegator.findList("TestingNode", isRoot, UtilMisc.toSet("testingNodeId"), null, null, false);
 
         for (GenericValue value: rootValues) {

Modified: ofbiz/branches/executioncontext20090812/framework/entityext/src/org/ofbiz/entityext/synchronization/EntitySyncServices.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/executioncontext20090812/framework/entityext/src/org/ofbiz/entityext/synchronization/EntitySyncServices.java?rev=805519&r1=805518&r2=805519&view=diff
==============================================================================
--- ofbiz/branches/executioncontext20090812/framework/entityext/src/org/ofbiz/entityext/synchronization/EntitySyncServices.java (original)
+++ ofbiz/branches/executioncontext20090812/framework/entityext/src/org/ofbiz/entityext/synchronization/EntitySyncServices.java Tue Aug 18 18:10:44 2009
@@ -42,7 +42,6 @@
 import org.ofbiz.base.util.UtilXml;
 import org.ofbiz.base.util.UtilURL;
 import org.ofbiz.entity.DelegatorFactory;
-import org.ofbiz.entity.EntityFactory;
 import org.ofbiz.entity.GenericDelegator;
 import org.ofbiz.entity.GenericEntity;
 import org.ofbiz.entity.GenericEntityException;

Modified: ofbiz/branches/executioncontext20090812/framework/minilang/src/org/ofbiz/minilang/SimpleMethod.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/executioncontext20090812/framework/minilang/src/org/ofbiz/minilang/SimpleMethod.java?rev=805519&r1=805518&r2=805519&view=diff
==============================================================================
--- ofbiz/branches/executioncontext20090812/framework/minilang/src/org/ofbiz/minilang/SimpleMethod.java (original)
+++ ofbiz/branches/executioncontext20090812/framework/minilang/src/org/ofbiz/minilang/SimpleMethod.java Tue Aug 18 18:10:44 2009
@@ -45,7 +45,7 @@
 import org.ofbiz.base.util.UtilValidate;
 import org.ofbiz.base.util.UtilXml;
 import org.ofbiz.base.util.cache.UtilCache;
-import org.ofbiz.entity.EntityFactory;
+import org.ofbiz.entity.GenericEntity;
 import org.ofbiz.entity.GenericValue;
 import org.ofbiz.entity.transaction.GenericTransactionException;
 import org.ofbiz.entity.transaction.TransactionUtil;
@@ -632,8 +632,8 @@
     /** Execute the Simple Method operations */
     public String exec(MethodContext methodContext) {
         // always put the null field object in as "null"
-        methodContext.putEnv("null", EntityFactory.NULL_FIELD);
-        methodContext.putEnv("nullField", EntityFactory.NULL_FIELD);
+        methodContext.putEnv("null", GenericEntity.NULL_FIELD);
+        methodContext.putEnv("nullField", GenericEntity.NULL_FIELD);
 
         methodContext.putEnv(delegatorName, methodContext.getDelegator());
         methodContext.putEnv(securityName, methodContext.getSecurity());

Added: ofbiz/branches/executioncontext20090812/framework/testtools/OFBizSeleniumXmlIntro.pdf
URL: http://svn.apache.org/viewvc/ofbiz/branches/executioncontext20090812/framework/testtools/OFBizSeleniumXmlIntro.pdf?rev=805519&view=auto
==============================================================================
Binary file - no diff available.

Propchange: ofbiz/branches/executioncontext20090812/framework/testtools/OFBizSeleniumXmlIntro.pdf
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: ofbiz/branches/executioncontext20090812/framework/testtools/convertSeleniumIDE.bat
URL: http://svn.apache.org/viewvc/ofbiz/branches/executioncontext20090812/framework/testtools/convertSeleniumIDE.bat?rev=805519&view=auto
==============================================================================
--- ofbiz/branches/executioncontext20090812/framework/testtools/convertSeleniumIDE.bat (added)
+++ ofbiz/branches/executioncontext20090812/framework/testtools/convertSeleniumIDE.bat Tue Aug 18 18:10:44 2009
@@ -0,0 +1,16 @@
+set OFBIZ_HOME=../..
+set CP=./build/lib/ofbiz-testtools.jar
+set CP=%CP%;./lib/httpclient-4.0-beta1.jar
+set CP=%CP%;./lib/selenium-java-client-driver.jar
+set CP=%CP%;%OFBIZ_HOME%/framework/base/lib/jdom-1.1.jar
+set CP=%CP%;%OFBIZ_HOME%/framework/base/lib/scripting/jython-nooro.jar
+set CP=%CP%;%OFBIZ_HOME%/framework/base/lib/junit.jar
+set CP=%CP%;%OFBIZ_HOME%/framework/base/lib/commons/commons-lang-2.3.jar
+set CP=%CP%;%OFBIZ_HOME%/framework/base/lib/log4j-1.2.15.jar
+
+rem echo %CP%
+
+rem For Example:
+rem convertSeleniumIDE.bat <recorded_script> <converted_script>
+
+"%JAVA_HOME%/bin/java.exe" -cp %CP% org.ofbiz.testtools.seleniumxml.SeleniumIDEConverter %1 %2

Added: ofbiz/branches/executioncontext20090812/framework/testtools/convertSeleniumIDE.sh
URL: http://svn.apache.org/viewvc/ofbiz/branches/executioncontext20090812/framework/testtools/convertSeleniumIDE.sh?rev=805519&view=auto
==============================================================================
--- ofbiz/branches/executioncontext20090812/framework/testtools/convertSeleniumIDE.sh (added)
+++ ofbiz/branches/executioncontext20090812/framework/testtools/convertSeleniumIDE.sh Tue Aug 18 18:10:44 2009
@@ -0,0 +1,24 @@
+#!/bin/sh
+export OFBIZ_HOME=../..
+export CP=./build/lib/ofbiz-testtools.jar
+export CP=$CP:./lib/httpclient-4.0-beta1.jar
+export CP=$CP:./lib/selenium-java-client-driver.jar
+export CP=$CP:$OFBIZ_HOME/framework/base/lib/jdom-1.1.jar
+export CP=$CP:$OFBIZ_HOME/framework/base/lib/scripting/jython-nooro.jar
+export CP=$CP:$OFBIZ_HOME/framework/base/lib/junit.jar
+export CP=$CP:$OFBIZ_HOME/framework/base/lib/commons/commons-lang-2.3.jar
+export CP=$CP:$OFBIZ_HOME/framework/base/lib/log4j-1.2.15.jar
+
+# echo $CP
+
+# For Example:
+# convertSeleniumIDE.bat <recorded_script> <converted_script>
+
+if [ -f "$JAVA_HOME/bin/java" ]; then
+  JAVA="$JAVA_HOME/bin/java"
+else
+  JAVA=java
+fi
+
+"$JAVA" -cp $CP org.ofbiz.testtools.seleniumxml.SeleniumIDEConverter "$@"
+exit 0