svn commit: r1652852 [5/22] - in /ofbiz/trunk: applications/content/src/org/ofbiz/content/cms/ applications/content/src/org/ofbiz/content/content/ applications/content/src/org/ofbiz/content/data/ applications/content/src/org/ofbiz/content/output/ appli...

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

svn commit: r1652852 [5/22] - in /ofbiz/trunk: applications/content/src/org/ofbiz/content/cms/ applications/content/src/org/ofbiz/content/content/ applications/content/src/org/ofbiz/content/data/ applications/content/src/org/ofbiz/content/output/ appli...

adrianc
Added: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelForm.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelForm.java?rev=1652852&view=auto
==============================================================================
--- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelForm.java (added)
+++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelForm.java Sun Jan 18 21:03:40 2015
@@ -0,0 +1,1854 @@
+/*******************************************************************************
+ * 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.widget.model;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.ofbiz.base.util.BshUtil;
+import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.StringUtil;
+import org.ofbiz.base.util.UtilCodec;
+import org.ofbiz.base.util.UtilGenerics;
+import org.ofbiz.base.util.UtilProperties;
+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.GenericEntityException;
+import org.ofbiz.entity.model.ModelEntity;
+import org.ofbiz.entity.model.ModelField;
+import org.ofbiz.entity.model.ModelReader;
+import org.ofbiz.service.DispatchContext;
+import org.ofbiz.service.GenericServiceException;
+import org.ofbiz.service.ModelParam;
+import org.ofbiz.service.ModelService;
+import org.ofbiz.widget.WidgetWorker;
+import org.ofbiz.widget.renderer.FormStringRenderer;
+import org.w3c.dom.Element;
+
+import bsh.EvalError;
+import bsh.Interpreter;
+
+/**
+ * Models the <form> element.
+ *
+ * @see <code>widget-form.xsd</code>
+ */
+@SuppressWarnings("serial")
+public class ModelForm extends ModelWidget {
+
+    /*
+     * ----------------------------------------------------------------------- *
+     *                     DEVELOPERS PLEASE READ
+     * ----------------------------------------------------------------------- *
+     *
+     * This model is intended to be a read-only data structure that represents
+     * an XML element. Outside of object construction, the class should not
+     * have any behaviors. All behavior should be contained in model visitors.
+     *
+     * Instances of this class will be shared by multiple threads - therefore
+     * it is immutable. DO NOT CHANGE THE OBJECT'S STATE AT RUN TIME!
+     *
+     * BE VERY CAREFUL when implementing "extends" - parent form collections
+     * must be added to child collections, not replace them. In other words,
+     * do not assign parent collection fields to child collection fields.
+     *
+     */
+
+    public static final String module = ModelForm.class.getName();
+    public static final String DEFAULT_FORM_RESULT_LIST_NAME = "defaultFormResultList";
+    /** Pagination settings and defaults. */
+    public static int DEFAULT_PAGE_SIZE = 10;
+    public static int MAX_PAGE_SIZE = 10000;
+    public static String DEFAULT_PAG_INDEX_FIELD = "viewIndex";
+    public static String DEFAULT_PAG_SIZE_FIELD = "viewSize";
+    public static String DEFAULT_PAG_STYLE = "nav-pager";
+    public static String DEFAULT_PAG_FIRST_STYLE = "nav-first";
+    public static String DEFAULT_PAG_PREV_STYLE = "nav-previous";
+    public static String DEFAULT_PAG_NEXT_STYLE = "nav-next";
+    public static String DEFAULT_PAG_LAST_STYLE = "nav-last";
+    /** Sort field default styles. */
+    public static String DEFAULT_SORT_FIELD_STYLE = "sort-order";
+    public static String DEFAULT_SORT_FIELD_ASC_STYLE = "sort-order-asc";
+    public static String DEFAULT_SORT_FIELD_DESC_STYLE = "sort-order-desc";
+    private final List<ModelAction> actions;
+    private final List<AltRowStyle> altRowStyles;
+    private final List<AltTarget> altTargets;
+    private final List<AutoFieldsEntity> autoFieldsEntities;
+    private final List<AutoFieldsService> autoFieldsServices;
+    private final boolean clientAutocompleteFields;
+    private final String containerId;
+    private final String containerStyle;
+    private final String defaultEntityName;
+    /** This field group will be the "catch-all" group for fields that are not
+     *  included in an explicit field-group.
+     */
+    private final FieldGroup defaultFieldGroup;
+    private final FlexibleMapAccessor<Map<String, ? extends Object>> defaultMapName;
+    private final String defaultRequiredFieldStyle;
+    private final String defaultServiceName;
+    private final String defaultSortFieldAscStyle;
+    private final String defaultSortFieldDescStyle;
+    private final String defaultSortFieldStyle;
+    private final String defaultTableStyle;
+    private final String defaultTitleAreaStyle;
+    private final String defaultTitleStyle;
+    private final String defaultTooltipStyle;
+    private final int defaultViewSize;
+    private final String defaultWidgetAreaStyle;
+    private final String defaultWidgetStyle;
+    private final String evenRowStyle;
+    /** This is a list of FieldGroups in the order they were created.
+     * Can also include Banner objects.
+     */
+    private final List<FieldGroupBase> fieldGroupList;
+    /** This Map is keyed with the field name and has a FieldGroup for the value.
+     * Can also include Banner objects.
+     */
+    private final Map<String, FieldGroupBase> fieldGroupMap;
+    /** This List will contain one copy of each field for each field name in the order
+     * they were encountered in the service, entity, or form definition; field definitions
+     * with constraints will also be in this list but may appear multiple times for the same
+     * field name.
+     *
+     * When rendering the form the order in this list should be following and it should not be
+     * necessary to use the Map. The Map is used when loading the form definition to keep the
+     * list clean and implement the override features for field definitions.
+     */
+    private final List<ModelFormField> fieldList;
+    private final String focusFieldName;
+    private final String formLocation;
+    private final String formTitleAreaStyle;
+    private final String formWidgetAreaStyle;
+    private final boolean groupColumns;
+    private final String headerRowStyle;
+    private final boolean hideHeader;
+    private final String itemIndexSeparator;
+    private final List<String> lastOrderFields;
+    private final String listEntryName;
+    private final String listName;
+    private final List<ModelFormField> multiSubmitFields;
+    private final String oddRowStyle;
+    /** On Paginate areas to be updated. */
+    private final List<UpdateArea> onPaginateUpdateAreas;
+    /** On Sort Column areas to be updated. */
+    private final List<UpdateArea> onSortColumnUpdateAreas;
+    /** On Submit areas to be updated. */
+    private final List<UpdateArea> onSubmitUpdateAreas;
+    private final FlexibleStringExpander overrideListSize;
+    private final FlexibleStringExpander paginate;
+    private final FlexibleStringExpander paginateFirstLabel;
+    private final FlexibleStringExpander paginateIndexField;
+    private final FlexibleStringExpander paginateLastLabel;
+    private final FlexibleStringExpander paginateNextLabel;
+    private final FlexibleStringExpander paginatePreviousLabel;
+    private final FlexibleStringExpander paginateSizeField;
+    private final String paginateStyle;
+    private final FlexibleStringExpander paginateTarget;
+    private final String paginateTargetAnchor;
+    private final FlexibleStringExpander paginateViewSizeLabel;
+    private final ModelForm parentModelForm;
+    private final List<ModelAction> rowActions;
+    private final FlexibleStringExpander rowCountExdr;
+    private final boolean separateColumns;
+    private final boolean skipEnd;
+    private final boolean skipStart;
+    private final String sortFieldParameterName;
+    private final List<SortField> sortOrderFields;
+    private final FlexibleStringExpander target;
+    private final String targetType;
+    private final FlexibleStringExpander targetWindowExdr;
+    private final String title;
+    private final String tooltip;
+    private final String type;
+    private final boolean useRowSubmit;
+    /** Keeps track of conditional fields to help ensure that only one is rendered
+     */
+    private final Set<String> useWhenFields;
+
+    /** XML Constructor */
+    public ModelForm(Element formElement, String formLocation, ModelReader entityModelReader, DispatchContext dispatchContext) {
+        super(formElement);
+        this.formLocation = formLocation;
+        parentModelForm = getParentForm(formElement, entityModelReader, dispatchContext);
+        int defaultViewSizeInt = DEFAULT_PAGE_SIZE;
+        String viewSize = formElement.getAttribute("view-size");
+        if (viewSize.isEmpty()) {
+            if (parentModelForm != null) {
+                defaultViewSizeInt = parentModelForm.defaultViewSize;
+            } else {
+                defaultViewSizeInt = UtilProperties.getPropertyAsInteger("widget.properties", "widget.form.defaultViewSize",
+                        defaultViewSizeInt);
+            }
+        } else {
+            try {
+                defaultViewSizeInt = Integer.valueOf(viewSize);
+            } catch (NumberFormatException e) {
+            }
+        }
+        this.defaultViewSize = defaultViewSizeInt;
+        String type = formElement.getAttribute("type");
+        if (type.isEmpty() && parentModelForm != null) {
+            type = parentModelForm.type;
+        }
+        this.type = type;
+        FlexibleStringExpander target = FlexibleStringExpander.getInstance(formElement.getAttribute("target"));
+        if (target.isEmpty() && parentModelForm != null) {
+            target = parentModelForm.target;
+        }
+        this.target = target;
+        String containerId = formElement.getAttribute("id");
+        if (containerId.isEmpty() && parentModelForm != null) {
+            containerId = parentModelForm.containerId;
+        }
+        this.containerId = containerId;
+        String containerStyle = formElement.getAttribute("style");
+        if (containerStyle.isEmpty() && parentModelForm != null) {
+            containerStyle = parentModelForm.containerStyle;
+        }
+        this.containerStyle = containerStyle;
+        String title = formElement.getAttribute("title");
+        if (title.isEmpty() && parentModelForm != null) {
+            title = parentModelForm.title;
+        }
+        this.title = title;
+        String tooltip = formElement.getAttribute("tooltip");
+        if (tooltip.isEmpty() && parentModelForm != null) {
+            tooltip = parentModelForm.tooltip;
+        }
+        this.tooltip = tooltip;
+        String listName = formElement.getAttribute("list-name");
+        if (listName.isEmpty()) {
+            if (parentModelForm != null) {
+                listName = parentModelForm.listName;
+            } else {
+                listName = DEFAULT_FORM_RESULT_LIST_NAME;
+            }
+        }
+        this.listName = listName;
+        String listEntryName = formElement.getAttribute("list-entry-name");
+        if (listEntryName.isEmpty() && parentModelForm != null) {
+            listEntryName = parentModelForm.listEntryName;
+        }
+        this.listEntryName = listEntryName;
+        String defaultEntityName = formElement.getAttribute("default-entity-name");
+        if (defaultEntityName.isEmpty() && parentModelForm != null) {
+            defaultEntityName = parentModelForm.defaultEntityName;
+        }
+        this.defaultEntityName = defaultEntityName;
+        String defaultServiceName = formElement.getAttribute("default-service-name");
+        if (defaultServiceName.isEmpty() && parentModelForm != null) {
+            defaultServiceName = parentModelForm.defaultServiceName;
+        }
+        this.defaultServiceName = defaultServiceName;
+        String formTitleAreaStyle = formElement.getAttribute("form-title-area-style");
+        if (formTitleAreaStyle.isEmpty() && parentModelForm != null) {
+            formTitleAreaStyle = parentModelForm.formTitleAreaStyle;
+        }
+        this.formTitleAreaStyle = formTitleAreaStyle;
+        String formWidgetAreaStyle = formElement.getAttribute("form-widget-area-style");
+        if (formWidgetAreaStyle.isEmpty() && parentModelForm != null) {
+            formWidgetAreaStyle = parentModelForm.formWidgetAreaStyle;
+        }
+        this.formWidgetAreaStyle = formWidgetAreaStyle;
+        String defaultTitleAreaStyle = formElement.getAttribute("default-title-area-style");
+        if (defaultTitleAreaStyle.isEmpty() && parentModelForm != null) {
+            defaultTitleAreaStyle = parentModelForm.defaultTitleAreaStyle;
+        }
+        this.defaultTitleAreaStyle = defaultTitleAreaStyle;
+        String defaultWidgetAreaStyle = formElement.getAttribute("default-widget-area-style");
+        if (defaultWidgetAreaStyle.isEmpty() && parentModelForm != null) {
+            defaultWidgetAreaStyle = parentModelForm.defaultWidgetAreaStyle;
+        }
+        this.defaultWidgetAreaStyle = defaultWidgetAreaStyle;
+        String oddRowStyle = formElement.getAttribute("odd-row-style");
+        if (oddRowStyle.isEmpty() && parentModelForm != null) {
+            oddRowStyle = parentModelForm.oddRowStyle;
+        }
+        this.oddRowStyle = oddRowStyle;
+        String evenRowStyle = formElement.getAttribute("even-row-style");
+        if (evenRowStyle.isEmpty() && parentModelForm != null) {
+            evenRowStyle = parentModelForm.evenRowStyle;
+        }
+        this.evenRowStyle = evenRowStyle;
+        String defaultTableStyle = formElement.getAttribute("default-table-style");
+        if (defaultTableStyle.isEmpty() && parentModelForm != null) {
+            defaultTableStyle = parentModelForm.defaultTableStyle;
+        }
+        this.defaultTableStyle = defaultTableStyle;
+        String headerRowStyle = formElement.getAttribute("header-row-style");
+        if (headerRowStyle.isEmpty() && parentModelForm != null) {
+            headerRowStyle = parentModelForm.headerRowStyle;
+        }
+        this.headerRowStyle = headerRowStyle;
+        String defaultTitleStyle = formElement.getAttribute("default-title-style");
+        if (defaultTitleStyle.isEmpty() && parentModelForm != null) {
+            defaultTitleStyle = parentModelForm.defaultTitleStyle;
+        }
+        this.defaultTitleStyle = defaultTitleStyle;
+        String defaultWidgetStyle = formElement.getAttribute("default-widget-style");
+        if (defaultWidgetStyle.isEmpty() && parentModelForm != null) {
+            defaultWidgetStyle = parentModelForm.defaultWidgetStyle;
+        }
+        this.defaultWidgetStyle = defaultWidgetStyle;
+        String defaultTooltipStyle = formElement.getAttribute("default-tooltip-style");
+        if (defaultTooltipStyle.isEmpty() && parentModelForm != null) {
+            defaultTooltipStyle = parentModelForm.defaultTooltipStyle;
+        }
+        this.defaultTooltipStyle = defaultTooltipStyle;
+        String itemIndexSeparator = formElement.getAttribute("item-index-separator");
+        if (itemIndexSeparator.isEmpty() && parentModelForm != null) {
+            itemIndexSeparator = parentModelForm.itemIndexSeparator;
+        }
+        this.itemIndexSeparator = itemIndexSeparator;
+        String separateColumns = formElement.getAttribute("separate-columns");
+        if (separateColumns.isEmpty() && parentModelForm != null) {
+            this.separateColumns = parentModelForm.separateColumns;
+        } else {
+            this.separateColumns = "true".equals(separateColumns);
+        }
+        String groupColumns = formElement.getAttribute("group-columns");
+        if (groupColumns.isEmpty() && parentModelForm != null) {
+            this.groupColumns = parentModelForm.groupColumns;
+        } else {
+            this.groupColumns = !"false".equals(groupColumns);
+        }
+        String targetType = formElement.getAttribute("target-type");
+        if (targetType.isEmpty() && parentModelForm != null) {
+            targetType = parentModelForm.targetType;
+        }
+        this.targetType = targetType;
+        FlexibleMapAccessor<Map<String, ? extends Object>> defaultMapName = FlexibleMapAccessor.getInstance(formElement
+                .getAttribute("default-map-name"));
+        if (defaultMapName.isEmpty() && parentModelForm != null) {
+            defaultMapName = parentModelForm.defaultMapName;
+        }
+        this.defaultMapName = defaultMapName;
+        FlexibleStringExpander targetWindowExdr = FlexibleStringExpander.getInstance(formElement.getAttribute("target-window"));
+        if (targetWindowExdr.isEmpty() && parentModelForm != null) {
+            targetWindowExdr = parentModelForm.targetWindowExdr;
+        }
+        this.targetWindowExdr = targetWindowExdr;
+        String hideHeader = formElement.getAttribute("hide-header");
+        if (hideHeader.isEmpty() && parentModelForm != null) {
+            this.hideHeader = parentModelForm.hideHeader;
+        } else {
+            this.hideHeader = "true".equals(hideHeader);
+        }
+        String clientAutocompleteFields = formElement.getAttribute("client-autocomplete-fields");
+        if (clientAutocompleteFields.isEmpty() && parentModelForm != null) {
+            this.clientAutocompleteFields = parentModelForm.clientAutocompleteFields;
+        } else {
+            this.clientAutocompleteFields = !"false".equals(formElement.getAttribute("client-autocomplete-fields"));
+        }
+        FlexibleStringExpander paginateTarget = FlexibleStringExpander.getInstance(formElement.getAttribute("paginate-target"));
+        if (paginateTarget.isEmpty() && parentModelForm != null) {
+            paginateTarget = parentModelForm.paginateTarget;
+        }
+        this.paginateTarget = paginateTarget;
+        ArrayList<AltTarget> altTargets = new ArrayList<AltTarget>();
+        if (parentModelForm != null) {
+            altTargets.addAll(parentModelForm.altTargets);
+        }
+        for (Element altTargetElement : UtilXml.childElementList(formElement, "alt-target")) {
+            altTargets.add(new AltTarget(altTargetElement));
+        }
+        altTargets.trimToSize();
+        this.altTargets = Collections.unmodifiableList(altTargets);
+        ArrayList<ModelAction> actions = new ArrayList<ModelAction>();
+        if (parentModelForm != null) {
+            actions.addAll(parentModelForm.actions);
+        }
+        Element actionsElement = UtilXml.firstChildElement(formElement, "actions");
+        if (actionsElement != null) {
+            actions.addAll(ModelFormAction.readSubActions(this, actionsElement));
+        }
+        actions.trimToSize();
+        this.actions = Collections.unmodifiableList(actions);
+        ArrayList<ModelAction> rowActions = new ArrayList<ModelAction>();
+        if (parentModelForm != null) {
+            rowActions.addAll(parentModelForm.rowActions);
+        }
+        Element rowActionsElement = UtilXml.firstChildElement(formElement, "row-actions");
+        if (rowActionsElement != null) {
+            rowActions.addAll(ModelFormAction.readSubActions(this, rowActionsElement));
+        }
+        rowActions.trimToSize();
+        this.rowActions = Collections.unmodifiableList(rowActions);
+        ArrayList<UpdateArea> onPaginateUpdateAreas = new ArrayList<UpdateArea>();
+        ArrayList<UpdateArea> onSubmitUpdateAreas = new ArrayList<UpdateArea>();
+        ArrayList<UpdateArea> onSortColumnUpdateAreas = new ArrayList<UpdateArea>();
+        if (parentModelForm != null) {
+            onPaginateUpdateAreas.addAll(parentModelForm.onPaginateUpdateAreas);
+            onSubmitUpdateAreas.addAll(parentModelForm.onSubmitUpdateAreas);
+            onSortColumnUpdateAreas.addAll(parentModelForm.onSortColumnUpdateAreas);
+        }
+        for (Element updateAreaElement : UtilXml.childElementList(formElement, "on-event-update-area")) {
+            UpdateArea updateArea = new UpdateArea(updateAreaElement, defaultServiceName, defaultEntityName);
+            if ("paginate".equals(updateArea.getEventType())) {
+                int index = onPaginateUpdateAreas.indexOf(updateArea);
+                if (index != -1) {
+                    if (!updateArea.areaTarget.isEmpty()) {
+                        onPaginateUpdateAreas.set(index, updateArea);
+                    } else {
+                        // blank target indicates a removing override
+                        onPaginateUpdateAreas.remove(index);
+                    }
+                } else {
+                    onPaginateUpdateAreas.add(updateArea);
+                }
+            } else if ("submit".equals(updateArea.getEventType())) {
+                int index = onSubmitUpdateAreas.indexOf(updateArea);
+                if (index != -1) {
+                    onSubmitUpdateAreas.set(index, updateArea);
+                } else {
+                    onSubmitUpdateAreas.add(updateArea);
+                }
+            } else if ("sort-column".equals(updateArea.getEventType())) {
+                int index = onSortColumnUpdateAreas.indexOf(updateArea);
+                if (index != -1) {
+                    if (!updateArea.areaTarget.isEmpty()) {
+                        onSortColumnUpdateAreas.set(index, updateArea);
+                    } else {
+                        // blank target indicates a removing override
+                        onSortColumnUpdateAreas.remove(index);
+                    }
+                } else {
+                    onSortColumnUpdateAreas.add(updateArea);
+                }
+            }
+        }
+        onPaginateUpdateAreas.trimToSize();
+        this.onPaginateUpdateAreas = Collections.unmodifiableList(onPaginateUpdateAreas);
+        onSubmitUpdateAreas.trimToSize();
+        this.onSubmitUpdateAreas = Collections.unmodifiableList(onSubmitUpdateAreas);
+        onSortColumnUpdateAreas.trimToSize();
+        this.onSortColumnUpdateAreas = Collections.unmodifiableList(onSortColumnUpdateAreas);
+        ArrayList<AltRowStyle> altRowStyles = new ArrayList<AltRowStyle>();
+        if (parentModelForm != null) {
+            altRowStyles.addAll(parentModelForm.altRowStyles);
+        }
+        for (Element altRowStyleElement : UtilXml.childElementList(formElement, "alt-row-style")) {
+            AltRowStyle altRowStyle = new AltRowStyle(altRowStyleElement);
+            altRowStyles.add(altRowStyle);
+        }
+        altRowStyles.trimToSize();
+        this.altRowStyles = Collections.unmodifiableList(altRowStyles);
+        Set<String> useWhenFields = new HashSet<String>();
+        if (parentModelForm != null) {
+            useWhenFields.addAll(parentModelForm.useWhenFields);
+        }
+        ArrayList<ModelFormFieldBuilder> fieldBuilderList = new ArrayList<ModelFormFieldBuilder>();
+        Map<String, ModelFormFieldBuilder> fieldBuilderMap = new HashMap<String, ModelFormFieldBuilder>();
+        if (parentModelForm != null) {
+            // Create this fieldList/Map from clones of parentModelForm's
+            for (ModelFormField parentChildField : parentModelForm.fieldList) {
+                ModelFormFieldBuilder builder = new ModelFormFieldBuilder(parentChildField);
+                builder.setModelForm(this);
+                fieldBuilderList.add(builder);
+                fieldBuilderMap.put(builder.getName(), builder);
+            }
+        }
+        Map<String, FieldGroupBase> fieldGroupMap = new HashMap<String, FieldGroupBase>();
+        if (parentModelForm != null) {
+            fieldGroupMap.putAll(parentModelForm.fieldGroupMap);
+        }
+        ArrayList<FieldGroupBase> fieldGroupList = new ArrayList<FieldGroupBase>();
+        if (parentModelForm != null) {
+            fieldGroupList.addAll(parentModelForm.fieldGroupList);
+        }
+        ArrayList<String> lastOrderFields = new ArrayList<String>();
+        if (parentModelForm != null) {
+            lastOrderFields.addAll(parentModelForm.lastOrderFields);
+        }
+        String sortFieldParameterName = formElement.getAttribute("sort-field-parameter-name");
+        if (sortFieldParameterName.isEmpty() && parentModelForm != null) {
+            this.sortFieldParameterName = parentModelForm.targetType;
+        } else {
+            this.sortFieldParameterName = "sortField";
+        }
+        String defaultRequiredFieldStyle = formElement.getAttribute("default-required-field-style");
+        if (defaultRequiredFieldStyle.isEmpty() && parentModelForm != null) {
+            defaultRequiredFieldStyle = parentModelForm.defaultRequiredFieldStyle;
+        }
+        this.defaultRequiredFieldStyle = defaultRequiredFieldStyle;
+        String defaultSortFieldStyle = formElement.getAttribute("default-sort-field-style");
+        if (defaultSortFieldStyle.isEmpty() && parentModelForm != null) {
+            this.defaultSortFieldStyle = parentModelForm.defaultSortFieldStyle;
+        } else {
+            this.defaultSortFieldStyle = DEFAULT_SORT_FIELD_STYLE;
+        }
+        String defaultSortFieldAscStyle = formElement.getAttribute("default-sort-field-asc-style");
+        if (defaultSortFieldAscStyle.isEmpty() && parentModelForm != null) {
+            this.defaultSortFieldAscStyle = parentModelForm.defaultSortFieldAscStyle;
+        } else {
+            this.defaultSortFieldAscStyle = DEFAULT_SORT_FIELD_ASC_STYLE;
+        }
+        String defaultSortFieldDescStyle = formElement.getAttribute("default-sort-field-desc-style");
+        if (defaultSortFieldDescStyle.isEmpty() && parentModelForm != null) {
+            this.defaultSortFieldDescStyle = parentModelForm.defaultSortFieldDescStyle;
+        } else {
+            this.defaultSortFieldDescStyle = DEFAULT_SORT_FIELD_DESC_STYLE;
+        }
+        String paginateTargetAnchor = formElement.getAttribute("paginate-target-anchor");
+        if (paginateTargetAnchor.isEmpty() && parentModelForm != null) {
+            paginateTargetAnchor = parentModelForm.paginateTargetAnchor;
+        }
+        this.paginateTargetAnchor = paginateTargetAnchor;
+        FlexibleStringExpander paginateIndexField = FlexibleStringExpander.getInstance(formElement
+                .getAttribute("paginate-index-field"));
+        if (paginateIndexField.isEmpty() && parentModelForm != null) {
+            paginateIndexField = parentModelForm.paginateIndexField;
+        }
+        this.paginateIndexField = paginateIndexField;
+        FlexibleStringExpander paginateSizeField = FlexibleStringExpander.getInstance(formElement
+                .getAttribute("paginate-size-field"));
+        if (paginateSizeField.isEmpty() && parentModelForm != null) {
+            paginateSizeField = parentModelForm.paginateSizeField;
+        }
+        this.paginateSizeField = paginateSizeField;
+        FlexibleStringExpander overrideListSize = FlexibleStringExpander.getInstance(formElement
+                .getAttribute("override-list-size"));
+        if (overrideListSize.isEmpty() && parentModelForm != null) {
+            overrideListSize = parentModelForm.overrideListSize;
+        }
+        this.overrideListSize = overrideListSize;
+        FlexibleStringExpander paginateFirstLabel = FlexibleStringExpander.getInstance(formElement
+                .getAttribute("paginate-first-label"));
+        if (paginateFirstLabel.isEmpty() && parentModelForm != null) {
+            paginateFirstLabel = parentModelForm.paginateFirstLabel;
+        }
+        this.paginateFirstLabel = paginateFirstLabel;
+        FlexibleStringExpander paginatePreviousLabel = FlexibleStringExpander.getInstance(formElement
+                .getAttribute("paginate-previous-label"));
+        if (paginatePreviousLabel.isEmpty() && parentModelForm != null) {
+            paginatePreviousLabel = parentModelForm.paginatePreviousLabel;
+        }
+        this.paginatePreviousLabel = paginatePreviousLabel;
+        FlexibleStringExpander paginateNextLabel = FlexibleStringExpander.getInstance(formElement
+                .getAttribute("paginate-next-label"));
+        if (paginateNextLabel.isEmpty() && parentModelForm != null) {
+            paginateNextLabel = parentModelForm.paginateNextLabel;
+        }
+        this.paginateNextLabel = paginateNextLabel;
+        FlexibleStringExpander paginateLastLabel = FlexibleStringExpander.getInstance(formElement
+                .getAttribute("paginate-last-label"));
+        if (paginateLastLabel.isEmpty() && parentModelForm != null) {
+            paginateLastLabel = parentModelForm.paginateLastLabel;
+        }
+        this.paginateLastLabel = paginateLastLabel;
+        FlexibleStringExpander paginateViewSizeLabel = FlexibleStringExpander.getInstance(formElement
+                .getAttribute("paginate-viewsize-label"));
+        if (paginateViewSizeLabel.isEmpty() && parentModelForm != null) {
+            paginateViewSizeLabel = parentModelForm.paginateViewSizeLabel;
+        }
+        this.paginateViewSizeLabel = paginateViewSizeLabel;
+        String paginateStyle = formElement.getAttribute("paginate-style");
+        if (paginateStyle.isEmpty() && parentModelForm != null) {
+            this.paginateStyle = parentModelForm.paginateStyle;
+        } else {
+            this.paginateStyle = DEFAULT_PAG_STYLE;
+        }
+        FlexibleStringExpander paginate = FlexibleStringExpander.getInstance(formElement.getAttribute("paginate"));
+        if (paginate.isEmpty() && parentModelForm != null) {
+            paginate = parentModelForm.paginate;
+        }
+        this.paginate = paginate;
+        String skipStart = formElement.getAttribute("skip-start");
+        if (skipStart.isEmpty() && parentModelForm != null) {
+            this.skipStart = parentModelForm.skipStart;
+        } else {
+            this.skipStart = "true".equals(skipStart);
+        }
+        String skipEnd = formElement.getAttribute("skip-end");
+        if (skipEnd.isEmpty() && parentModelForm != null) {
+            this.skipEnd = parentModelForm.skipEnd;
+        } else {
+            this.skipEnd = "true".equals(skipEnd);
+        }
+        String useRowSubmit = formElement.getAttribute("use-row-submit");
+        if (useRowSubmit.isEmpty() && parentModelForm != null) {
+            this.useRowSubmit = parentModelForm.useRowSubmit;
+        } else {
+            this.useRowSubmit = "true".equals(useRowSubmit);
+        }
+        FlexibleStringExpander rowCountExdr = FlexibleStringExpander.getInstance(formElement.getAttribute("row-count"));
+        if (rowCountExdr.isEmpty() && parentModelForm != null) {
+            rowCountExdr = parentModelForm.rowCountExdr;
+        }
+        this.rowCountExdr = paginate;
+        ArrayList<ModelFormFieldBuilder> multiSubmitBuilders = new ArrayList<ModelFormFieldBuilder>();
+        ArrayList<AutoFieldsService> autoFieldsServices = new ArrayList<AutoFieldsService>();
+        ArrayList<AutoFieldsEntity> autoFieldsEntities = new ArrayList<AutoFieldsEntity>();
+        ArrayList<SortField> sortOrderFields = new ArrayList<SortField>();
+        this.defaultFieldGroup = new FieldGroup(null, this, sortOrderFields, fieldGroupMap);
+        for (Element autoFieldsServiceElement : UtilXml.childElementList(formElement, "auto-fields-service")) {
+            AutoFieldsService autoFieldsService = new AutoFieldsService(autoFieldsServiceElement);
+            autoFieldsServices.add(autoFieldsService);
+            addAutoFieldsFromService(autoFieldsService, entityModelReader, dispatchContext, useWhenFields, fieldBuilderList, fieldBuilderMap);
+        }
+        for (Element autoFieldsEntityElement : UtilXml.childElementList(formElement, "auto-fields-entity")) {
+            AutoFieldsEntity autoFieldsEntity = new AutoFieldsEntity(autoFieldsEntityElement);
+            autoFieldsEntities.add(autoFieldsEntity);
+            addAutoFieldsFromEntity(autoFieldsEntity, entityModelReader, useWhenFields, fieldBuilderList, fieldBuilderMap);
+        }
+        String thisType = this.getType();
+        for (Element fieldElement : UtilXml.childElementList(formElement, "field")) {
+            ModelFormFieldBuilder builder = new ModelFormFieldBuilder(fieldElement, this, entityModelReader, dispatchContext);
+            FieldInfo fieldInfo = builder.getFieldInfo();
+            if (thisType.equals("multi") && fieldInfo instanceof ModelFormField.SubmitField) {
+                multiSubmitBuilders.add(builder);
+            } else {
+                addUpdateField(builder, useWhenFields, fieldBuilderList, fieldBuilderMap);
+            }
+        }
+        // get the sort-order
+        Element sortOrderElement = UtilXml.firstChildElement(formElement, "sort-order");
+        if (sortOrderElement != null) {
+            FieldGroup lastFieldGroup = new FieldGroup(null, this, sortOrderFields, fieldGroupMap);
+            fieldGroupList.add(lastFieldGroup);
+            // read in sort-field
+            for (Element sortFieldElement : UtilXml.childElementList(sortOrderElement)) {
+                String tagName = sortFieldElement.getTagName();
+                if (tagName.equals("sort-field")) {
+                    String fieldName = sortFieldElement.getAttribute("name");
+                    String position = sortFieldElement.getAttribute("position");
+                    sortOrderFields.add(new SortField(fieldName, position));
+                    fieldGroupMap.put(fieldName, lastFieldGroup);
+                } else if (tagName.equals("last-field")) {
+                    String fieldName = sortFieldElement.getAttribute("name");
+                    fieldGroupMap.put(fieldName, lastFieldGroup);
+                    lastOrderFields.add(fieldName);
+                } else if (tagName.equals("banner")) {
+                    Banner thisBanner = new Banner(sortFieldElement);
+                    fieldGroupList.add(thisBanner);
+                    lastFieldGroup = new FieldGroup(null, this, sortOrderFields, fieldGroupMap);
+                    fieldGroupList.add(lastFieldGroup);
+                } else if (tagName.equals("field-group")) {
+                    FieldGroup thisFieldGroup = new FieldGroup(sortFieldElement, this, sortOrderFields, fieldGroupMap);
+                    fieldGroupList.add(thisFieldGroup);
+                    lastFieldGroup = new FieldGroup(null, this, sortOrderFields, fieldGroupMap);
+                    fieldGroupList.add(lastFieldGroup);
+                }
+            }
+        }
+        if (sortOrderFields.size() > 0) {
+            ArrayList<ModelFormFieldBuilder> sortedFields = new ArrayList<ModelFormFieldBuilder>();
+            for (SortField sortField : sortOrderFields) {
+                String fieldName = sortField.getFieldName();
+                if (UtilValidate.isEmpty(fieldName)) {
+                    continue;
+                }
+                // get all fields with the given name from the existing list and put them in the sorted list
+                Iterator<ModelFormFieldBuilder> fieldIter = fieldBuilderList.iterator();
+                while (fieldIter.hasNext()) {
+                    ModelFormFieldBuilder builder = fieldIter.next();
+                    if (fieldName.equals(builder.getName())) {
+                        // matched the name; remove from the original last and add to the sorted list
+                        if (UtilValidate.isNotEmpty(sortField.getPosition())) {
+                            builder.setPosition(sortField.getPosition());
+                        }
+                        fieldIter.remove();
+                        sortedFields.add(builder);
+                    }
+                }
+            }
+            // now add all of the rest of the fields from fieldList, ie those that were not explicitly listed in the sort order
+            sortedFields.addAll(fieldBuilderList);
+            // sortedFields all done, set fieldList
+            fieldBuilderList = sortedFields;
+        }
+        if (UtilValidate.isNotEmpty(lastOrderFields)) {
+            List<ModelFormFieldBuilder> lastedFields = new LinkedList<ModelFormFieldBuilder>();
+            for (String fieldName : lastOrderFields) {
+                if (UtilValidate.isEmpty(fieldName)) {
+                    continue;
+                }
+                // get all fields with the given name from the existing list and put them in the lasted list
+                Iterator<ModelFormFieldBuilder> fieldIter = fieldBuilderList.iterator();
+                while (fieldIter.hasNext()) {
+                    ModelFormFieldBuilder builder = fieldIter.next();
+                    if (fieldName.equals(builder.getName())) {
+                        // matched the name; remove from the original last and add to the lasted list
+                        fieldIter.remove();
+                        lastedFields.add(builder);
+                    }
+                }
+            }
+            //now put all lastedFields at the field list end
+            fieldBuilderList.addAll(lastedFields);
+        }
+        List<ModelFormField> fieldList = new ArrayList<ModelFormField>(fieldBuilderList.size());
+        for (ModelFormFieldBuilder builder : fieldBuilderList) {
+            fieldList.add(builder.build());
+        }
+        this.fieldList = Collections.unmodifiableList(fieldList);
+        List<ModelFormField> multiSubmitFields = new ArrayList<ModelFormField>(multiSubmitBuilders.size());
+        for (ModelFormFieldBuilder builder : multiSubmitBuilders) {
+            multiSubmitFields.add(builder.build());
+        }
+        this.multiSubmitFields = Collections.unmodifiableList(multiSubmitFields);
+        this.useWhenFields = Collections.unmodifiableSet(useWhenFields);
+        this.fieldGroupMap = Collections.unmodifiableMap(fieldGroupMap);
+        fieldGroupList.trimToSize();
+        this.fieldGroupList = Collections.unmodifiableList(fieldGroupList);
+        lastOrderFields.trimToSize();
+        this.lastOrderFields = Collections.unmodifiableList(lastOrderFields);
+        autoFieldsServices.trimToSize();
+        this.autoFieldsServices = Collections.unmodifiableList(autoFieldsServices);
+        autoFieldsEntities.trimToSize();
+        this.autoFieldsEntities = Collections.unmodifiableList(autoFieldsEntities);
+        sortOrderFields.trimToSize();
+        this.sortOrderFields = Collections.unmodifiableList(sortOrderFields);
+        String focusFieldName = formElement.getAttribute("focus-field-name");
+        if (focusFieldName.isEmpty() && parentModelForm != null) {
+            focusFieldName = parentModelForm.focusFieldName;
+        }
+        this.focusFieldName = focusFieldName;
+    }
+
+    @Override
+    public void accept(ModelWidgetVisitor visitor) throws Exception {
+        visitor.visit(this);
+    }
+
+    private void addAutoFieldsFromEntity(AutoFieldsEntity autoFieldsEntity, ModelReader entityModelReader,
+            Set<String> useWhenFields, List<ModelFormFieldBuilder> fieldBuilderList, Map<String, ModelFormFieldBuilder> fieldBuilderMap) {
+        // read entity def and auto-create fields
+        ModelEntity modelEntity = null;
+        try {
+            modelEntity = entityModelReader.getModelEntity(autoFieldsEntity.entityName);
+        } catch (GenericEntityException e) {
+            Debug.logError(e, module);
+        }
+        if (modelEntity == null) {
+            throw new IllegalArgumentException("Error finding Entity with name " + autoFieldsEntity.entityName
+                    + " for auto-fields-entity in a form widget");
+        }
+        Iterator<ModelField> modelFieldIter = modelEntity.getFieldsIterator();
+        while (modelFieldIter.hasNext()) {
+            ModelField modelField = modelFieldIter.next();
+            if (modelField.getIsAutoCreatedInternal()) {
+                // don't ever auto-add these, should only be added if explicitly referenced
+                continue;
+            }
+            ModelFormFieldBuilder builder = new ModelFormFieldBuilder();
+            builder.setModelForm(this);
+            builder.setName(modelField.getName());
+            builder.setEntityName(modelEntity.getEntityName());
+            builder.setFieldName(modelField.getName());
+            builder.induceFieldInfoFromEntityField(modelEntity, modelField, autoFieldsEntity.defaultFieldType);
+            builder.setPosition(autoFieldsEntity.defaultPosition);
+            if (UtilValidate.isNotEmpty(autoFieldsEntity.mapName)) {
+                builder.setMapName(autoFieldsEntity.mapName);
+            }
+            addUpdateField(builder, useWhenFields, fieldBuilderList, fieldBuilderMap);
+        }
+    }
+
+    private void addAutoFieldsFromService(AutoFieldsService autoFieldsService, ModelReader entityModelReader,
+            DispatchContext dispatchContext, Set<String> useWhenFields, List<ModelFormFieldBuilder> fieldBuilderList,
+            Map<String, ModelFormFieldBuilder> fieldBuilderMap) {
+        // read service def and auto-create fields
+        ModelService modelService = null;
+        try {
+            modelService = dispatchContext.getModelService(autoFieldsService.serviceName);
+        } catch (GenericServiceException e) {
+            String errmsg = "Error finding Service with name " + autoFieldsService.serviceName
+                    + " for auto-fields-service in a form widget";
+            Debug.logError(e, errmsg, module);
+            throw new IllegalArgumentException(errmsg);
+        }
+        for (ModelParam modelParam : modelService.getInModelParamList()) {
+            if (modelParam.internal) {
+                // skip auto params that the service engine populates...
+                continue;
+            }
+            if (modelParam.formDisplay) {
+                if (UtilValidate.isNotEmpty(modelParam.entityName) && UtilValidate.isNotEmpty(modelParam.fieldName)) {
+                    ModelEntity modelEntity;
+                    try {
+                        modelEntity = entityModelReader.getModelEntity(modelParam.entityName);
+                        if (modelEntity != null) {
+                            ModelField modelField = modelEntity.getField(modelParam.fieldName);
+                            if (modelField != null) {
+                                // okay, populate using the entity field info...
+                                ModelFormFieldBuilder builder = new ModelFormFieldBuilder();
+                                builder.setModelForm(this);
+                                builder.setName(modelField.getName());
+                                builder.setEntityName(modelEntity.getEntityName());
+                                builder.setFieldName(modelField.getName());
+                                builder.induceFieldInfoFromEntityField(modelEntity, modelField, autoFieldsService.defaultFieldType);
+                                if (UtilValidate.isNotEmpty(autoFieldsService.mapName)) {
+                                    builder.setMapName(autoFieldsService.mapName);
+                                }
+                                builder.setRequiredField(!modelParam.optional);
+                                addUpdateField(builder, useWhenFields, fieldBuilderList, fieldBuilderMap);
+                                // continue to skip creating based on service param
+                                continue;
+                            }
+                        }
+                    } catch (GenericEntityException e) {
+                        Debug.logError(e, module);
+                    }
+                }
+                ModelFormFieldBuilder builder = new ModelFormFieldBuilder();
+                builder.setModelForm(this);
+                builder.setName(modelParam.name);
+                builder.setServiceName(modelService.name);
+                builder.setAttributeName(modelParam.name);
+                builder.setTitle(modelParam.formLabel);
+                builder.setRequiredField(!modelParam.optional);
+                builder.induceFieldInfoFromServiceParam(modelService, modelParam, autoFieldsService.defaultFieldType);
+                builder.setPosition(autoFieldsService.defaultPosition);
+                if (UtilValidate.isNotEmpty(autoFieldsService.mapName)) {
+                    builder.setMapName(autoFieldsService.mapName);
+                }
+                addUpdateField(builder, useWhenFields, fieldBuilderList, fieldBuilderMap);
+            }
+        }
+    }
+
+    private void addUpdateField(ModelFormFieldBuilder builder, Set<String> useWhenFields,
+            List<ModelFormFieldBuilder> fieldBuilderList, Map<String, ModelFormFieldBuilder> fieldBuilderMap) {
+        if (!builder.getUseWhen().isEmpty() || useWhenFields.contains(builder.getName())) {
+            useWhenFields.add(builder.getName());
+            // is a conditional field, add to the List but don't worry about the Map
+            //for adding to list, see if there is another field with that name in the list and if so, put it before that one
+            boolean inserted = false;
+            for (int i = 0; i < fieldBuilderList.size(); i++) {
+                ModelFormFieldBuilder curField = fieldBuilderList.get(i);
+                if (curField.getName() != null && curField.getName().equals(builder.getName())) {
+                    fieldBuilderList.add(i, builder);
+                    inserted = true;
+                    break;
+                }
+            }
+            if (!inserted) {
+                fieldBuilderList.add(builder);
+            }
+            return;
+        } else {
+            // not a conditional field, see if a named field exists in Map
+            ModelFormFieldBuilder existingField = fieldBuilderMap.get(builder.getName());
+            if (existingField != null) {
+                // does exist, update the field by doing a merge/override
+                existingField.mergeOverrideModelFormField(builder);
+            } else {
+                // does not exist, add to List and Map
+                fieldBuilderList.add(builder);
+                fieldBuilderMap.put(builder.getName(), builder);
+            }
+        }
+    }
+
+    public List<ModelAction> getActions() {
+        return actions;
+    }
+
+    public List<AltRowStyle> getAltRowStyles() {
+        return altRowStyles;
+    }
+
+    public List<AltTarget> getAltTargets() {
+        return altTargets;
+    }
+
+    public List<AutoFieldsEntity> getAutoFieldsEntities() {
+        return autoFieldsEntities;
+    }
+
+    public List<AutoFieldsService> getAutoFieldsServices() {
+        return autoFieldsServices;
+    }
+
+    public Interpreter getBshInterpreter(Map<String, Object> context) throws EvalError {
+        Interpreter bsh = (Interpreter) context.get("bshInterpreter");
+        if (bsh == null) {
+            bsh = BshUtil.makeInterpreter(context);
+            context.put("bshInterpreter", bsh);
+        }
+        return bsh;
+    }
+
+    @Override
+    public String getBoundaryCommentName() {
+        return formLocation + "#" + getName();
+    }
+
+    public boolean getClientAutocompleteFields() {
+        return this.clientAutocompleteFields;
+    }
+
+    public String getContainerId() {
+        // use the name if there is no id
+        if (UtilValidate.isNotEmpty(this.containerId)) {
+            return this.containerId;
+        } else {
+            return this.getName();
+        }
+    }
+
+    public String getContainerStyle() {
+        return this.containerStyle;
+    }
+
+    public String getDefaultEntityName() {
+        return this.defaultEntityName;
+    }
+
+    public FieldGroup getDefaultFieldGroup() {
+        return defaultFieldGroup;
+    }
+
+    public Map<String, ? extends Object> getDefaultMap(Map<String, ? extends Object> context) {
+        return this.defaultMapName.get(context);
+    }
+
+    public String getDefaultMapName() {
+        return this.defaultMapName.getOriginalName();
+    }
+
+    public String getDefaultRequiredFieldStyle() {
+        return this.defaultRequiredFieldStyle;
+    }
+
+    public String getDefaultServiceName() {
+        return this.defaultServiceName;
+    }
+
+    public String getDefaultSortFieldAscStyle() {
+        return this.defaultSortFieldAscStyle;
+    }
+
+    public String getDefaultSortFieldDescStyle() {
+        return this.defaultSortFieldDescStyle;
+    }
+
+    public String getDefaultSortFieldStyle() {
+        return this.defaultSortFieldStyle;
+    }
+
+    public String getDefaultTableStyle() {
+        return this.defaultTableStyle;
+    }
+
+    public String getDefaultTitleAreaStyle() {
+        return this.defaultTitleAreaStyle;
+    }
+
+    public String getDefaultTitleStyle() {
+        return this.defaultTitleStyle;
+    }
+
+    public String getDefaultTooltipStyle() {
+        return this.defaultTooltipStyle;
+    }
+
+    public int getDefaultViewSize() {
+        return defaultViewSize;
+    }
+
+    public String getDefaultWidgetAreaStyle() {
+        return this.defaultWidgetAreaStyle;
+    }
+
+    public String getDefaultWidgetStyle() {
+        return this.defaultWidgetStyle;
+    }
+
+    public String getEvenRowStyle() {
+        return this.evenRowStyle;
+    }
+
+    public List<FieldGroupBase> getFieldGroupList() {
+        return fieldGroupList;
+    }
+
+    public Map<String, FieldGroupBase> getFieldGroupMap() {
+        return fieldGroupMap;
+    }
+
+    public List<ModelFormField> getFieldList() {
+        return fieldList;
+    }
+
+    public String getFocusFieldName() {
+        return focusFieldName;
+    }
+
+    public String getFormLocation() {
+        return this.formLocation;
+    }
+
+    public String getFormTitleAreaStyle() {
+        return this.formTitleAreaStyle;
+    }
+
+    public String getFormWidgetAreaStyle() {
+        return this.formWidgetAreaStyle;
+    }
+
+    public String getHeaderRowStyle() {
+        return this.headerRowStyle;
+    }
+
+    public boolean getHideHeader() {
+        return this.hideHeader;
+    }
+
+    public String getItemIndexSeparator() {
+        if (UtilValidate.isNotEmpty(this.itemIndexSeparator)) {
+            return this.itemIndexSeparator;
+        } else {
+            return "_o_";
+        }
+    }
+
+    public List<String> getLastOrderFields() {
+        return lastOrderFields;
+    }
+
+    public String getListEntryName() {
+        return this.listEntryName;
+    }
+
+    public String getListName() {
+        return this.listName;
+    }
+
+    public String getMultiPaginateIndexField(Map<String, Object> context) {
+        String field = this.paginateIndexField.expandString(context);
+        if (UtilValidate.isEmpty(field)) {
+            field = DEFAULT_PAG_INDEX_FIELD;
+        }
+        //  append the paginator number
+        field = field + "_" + WidgetWorker.getPaginatorNumber(context);
+        return field;
+    }
+
+    public String getMultiPaginateSizeField(Map<String, Object> context) {
+        String field = this.paginateSizeField.expandString(context);
+        if (UtilValidate.isEmpty(field)) {
+            field = DEFAULT_PAG_SIZE_FIELD;
+        }
+        //  append the paginator number
+        field = field + "_" + WidgetWorker.getPaginatorNumber(context);
+        return field;
+    }
+
+    public List<ModelFormField> getMultiSubmitFields() {
+        return this.multiSubmitFields;
+    }
+
+    public String getOddRowStyle() {
+        return this.oddRowStyle;
+    }
+
+    public List<UpdateArea> getOnPaginateUpdateAreas() {
+        return this.onPaginateUpdateAreas;
+    }
+
+    public List<UpdateArea> getOnSortColumnUpdateAreas() {
+        return this.onSortColumnUpdateAreas;
+    }
+
+    /* Returns the list of ModelForm.UpdateArea objects.
+     */
+    public List<UpdateArea> getOnSubmitUpdateAreas() {
+        return this.onSubmitUpdateAreas;
+    }
+
+    public String getOverrideListSize() {
+        return overrideListSize.getOriginal();
+    }
+
+    public int getOverrideListSize(Map<String, Object> context) {
+        int listSize = 0;
+        if (!this.overrideListSize.isEmpty()) {
+            String size = this.overrideListSize.expandString(context);
+            try {
+                size = size.replaceAll("[^0-9.]", "");
+                listSize = Integer.parseInt(size);
+            } catch (NumberFormatException e) {
+                Debug.logError(e, "Error getting override list size from value " + size, module);
+            }
+        }
+        return listSize;
+    }
+
+    public String getPaginate() {
+        return paginate.getOriginal();
+    }
+
+    public boolean getPaginate(Map<String, Object> context) {
+        String paginate = this.paginate.expandString(context);
+        if (!paginate.isEmpty()) {
+            return Boolean.valueOf(paginate).booleanValue();
+        } else {
+            return true;
+        }
+    }
+
+    public String getPaginateFirstLabel() {
+        return paginateFirstLabel.getOriginal();
+    }
+
+    public String getPaginateFirstLabel(Map<String, Object> context) {
+        Locale locale = (Locale) context.get("locale");
+        String field = this.paginateFirstLabel.expandString(context);
+        if (UtilValidate.isEmpty(field)) {
+            field = UtilProperties.getMessage("CommonUiLabels", "CommonFirst", locale);
+        }
+        return field;
+    }
+
+    public String getPaginateFirstStyle() {
+        return DEFAULT_PAG_FIRST_STYLE;
+    }
+
+    public String getPaginateIndexField() {
+        return paginateIndexField.getOriginal();
+    }
+
+    public String getPaginateIndexField(Map<String, Object> context) {
+        String field = this.paginateIndexField.expandString(context);
+        if (field.isEmpty()) {
+            return DEFAULT_PAG_INDEX_FIELD;
+        }
+        return field;
+    }
+
+    public String getPaginateLastLabel() {
+        return paginateLastLabel.getOriginal();
+    }
+
+    public String getPaginateLastLabel(Map<String, Object> context) {
+        Locale locale = (Locale) context.get("locale");
+        String field = this.paginateLastLabel.expandString(context);
+        if (UtilValidate.isEmpty(field)) {
+            field = UtilProperties.getMessage("CommonUiLabels", "CommonLast", locale);
+        }
+        return field;
+    }
+
+    public String getPaginateLastStyle() {
+        return DEFAULT_PAG_LAST_STYLE;
+    }
+
+    public String getPaginateNextLabel() {
+        return paginateNextLabel.getOriginal();
+    }
+
+    public String getPaginateNextLabel(Map<String, Object> context) {
+        String field = this.paginateNextLabel.expandString(context);
+        if (field.isEmpty()) {
+            Locale locale = (Locale) context.get("locale");
+            return UtilProperties.getMessage("CommonUiLabels", "CommonNext", locale);
+        }
+        return field;
+    }
+
+    public String getPaginateNextStyle() {
+        return DEFAULT_PAG_NEXT_STYLE;
+    }
+
+    public String getPaginatePreviousLabel() {
+        return paginatePreviousLabel.getOriginal();
+    }
+
+    public String getPaginatePreviousLabel(Map<String, Object> context) {
+        String field = this.paginatePreviousLabel.expandString(context);
+        if (field.isEmpty()) {
+            Locale locale = (Locale) context.get("locale");
+            field = UtilProperties.getMessage("CommonUiLabels", "CommonPrevious", locale);
+        }
+        return field;
+    }
+
+    public String getPaginatePreviousStyle() {
+        return DEFAULT_PAG_PREV_STYLE;
+    }
+
+    public String getPaginateSizeField() {
+        return paginateSizeField.getOriginal();
+    }
+
+    public String getPaginateSizeField(Map<String, Object> context) {
+        String field = this.paginateSizeField.expandString(context);
+        if (field.isEmpty()) {
+            return DEFAULT_PAG_SIZE_FIELD;
+        }
+        return field;
+    }
+
+    public String getPaginateStyle() {
+        return this.paginateStyle;
+    }
+
+    public String getPaginateTarget() {
+        return paginateTarget.getOriginal();
+    }
+
+    public String getPaginateTarget(Map<String, Object> context) {
+        String targ = this.paginateTarget.expandString(context);
+        if (targ.isEmpty()) {
+            Map<String, ?> parameters = UtilGenerics.cast(context.get("parameters"));
+            if (parameters != null && parameters.containsKey("targetRequestUri")) {
+                targ = (String) parameters.get("targetRequestUri");
+            }
+        }
+        return targ;
+    }
+
+    public String getPaginateTargetAnchor() {
+        return this.paginateTargetAnchor;
+    }
+
+    public String getPaginateViewSizeLabel() {
+        return paginateViewSizeLabel.getOriginal();
+    }
+
+    public String getPaginateViewSizeLabel(Map<String, Object> context) {
+        String field = this.paginateViewSizeLabel.expandString(context);
+        if (field.isEmpty()) {
+            Locale locale = (Locale) context.get("locale");
+            return UtilProperties.getMessage("CommonUiLabels", "CommonItemsPerPage", locale);
+        }
+        return field;
+    }
+
+    private ModelForm getParentForm(Element formElement, ModelReader entityModelReader, DispatchContext dispatchContext) {
+        ModelForm parent = null;
+        String parentResource = formElement.getAttribute("extends-resource");
+        String parentForm = formElement.getAttribute("extends");
+        if (parentForm.length() > 0) {
+            // check if we have a resource name (part of the string before the ?)
+            if (parentResource.length() > 0) {
+                try {
+                    parent = FormFactory.getFormFromLocation(parentResource, parentForm, entityModelReader, dispatchContext);
+                } catch (Exception e) {
+                    Debug.logError(e, "Failed to load parent form definition '" + parentForm + "' at resource '" + parentResource
+                            + "'", module);
+                }
+            } else if (!parentForm.equals(formElement.getAttribute("name"))) {
+                // try to find a form definition in the same file
+                Element rootElement = formElement.getOwnerDocument().getDocumentElement();
+                List<? extends Element> formElements = UtilXml.childElementList(rootElement, "form");
+                //Uncomment below to add support for abstract forms
+                //formElements.addAll(UtilXml.childElementList(rootElement, "abstract-form"));
+                for (Element formElementEntry : formElements) {
+                    if (formElementEntry.getAttribute("name").equals(parentForm)) {
+                        parent = new ModelForm(formElementEntry, parentResource, entityModelReader, dispatchContext);
+                        break;
+                    }
+                }
+                if (parent == null) {
+                    Debug.logError("Failed to find parent form definition '" + parentForm + "' in same document.", module);
+                }
+            } else {
+                Debug.logError("Recursive form definition found for '" + formElement.getAttribute("name") + ".'", module);
+            }
+        }
+        return parent;
+    }
+
+    public String getParentFormLocation() {
+        return this.parentModelForm == null ? null : this.parentModelForm.getFormLocation();
+    }
+
+    public String getParentFormName() {
+        return this.parentModelForm == null ? null : this.parentModelForm.getName();
+    }
+
+    public ModelForm getParentModelForm() {
+        return parentModelForm;
+    }
+
+    public String getPassedRowCount(Map<String, Object> context) {
+        return rowCountExdr.expandString(context);
+    }
+
+    public List<ModelAction> getRowActions() {
+        return rowActions;
+    }
+
+    public String getRowCount() {
+        return rowCountExdr.getOriginal();
+    }
+
+    public boolean getSeparateColumns() {
+        return this.separateColumns;
+    }
+
+    public boolean getSkipEnd() {
+        return this.skipEnd;
+    }
+
+    public boolean getSkipStart() {
+        return this.skipStart;
+    }
+
+    public String getSortField(Map<String, Object> context) {
+        String value = null;
+        try {
+            value = (String) context.get(this.sortFieldParameterName);
+            if (value == null) {
+                Map<String, String> parameters = UtilGenerics.cast(context.get("parameters"));
+                if (parameters != null) {
+                    value = parameters.get(this.sortFieldParameterName);
+                }
+            }
+        } catch (Exception e) {
+            Debug.logWarning(e, "Error getting sortField: " + e.toString(), module);
+        }
+        return value;
+    }
+
+    public String getSortFieldParameterName() {
+        return this.sortFieldParameterName;
+    }
+
+    public List<SortField> getSortOrderFields() {
+        return sortOrderFields;
+    }
+
+    /**
+     * iterate through alt-row-styles list to see if should be used, then add style
+     * @return The style for item row
+     */
+    public String getStyleAltRowStyle(Map<String, Object> context) {
+        String styles = "";
+        try {
+            // use the same Interpreter (ie with the same context setup) for all evals
+            Interpreter bsh = this.getBshInterpreter(context);
+            for (AltRowStyle altRowStyle : this.altRowStyles) {
+                Object retVal = bsh.eval(StringUtil.convertOperatorSubstitutions(altRowStyle.useWhen));
+                // retVal should be a Boolean, if not something weird is up...
+                if (retVal instanceof Boolean) {
+                    Boolean boolVal = (Boolean) retVal;
+                    if (boolVal.booleanValue()) {
+                        styles += altRowStyle.style;
+                    }
+                } else {
+                    throw new IllegalArgumentException("Return value from style condition eval was not a Boolean: "
+                            + retVal.getClass().getName() + " [" + retVal + "] of form " + getName());
+                }
+            }
+        } catch (EvalError e) {
+            String errmsg = "Error evaluating BeanShell style conditions on form " + getName();
+            Debug.logError(e, errmsg, module);
+            throw new IllegalArgumentException(errmsg);
+        }
+        return styles;
+    }
+
+    public String getTarget() {
+        return target.getOriginal();
+    }
+
+    /** iterate through altTargets list to see if any should be used, if not return original target
+     * @return The target for this Form
+     */
+    public String getTarget(Map<String, Object> context, String targetType) {
+        Map<String, Object> expanderContext = context;
+        UtilCodec.SimpleEncoder simpleEncoder = (UtilCodec.SimpleEncoder) context.get("simpleEncoder");
+        if (simpleEncoder != null) {
+            expanderContext = UtilCodec.HtmlEncodingMapWrapper.getHtmlEncodingMapWrapper(context, simpleEncoder);
+        }
+        try {
+            // use the same Interpreter (ie with the same context setup) for all evals
+            Interpreter bsh = this.getBshInterpreter(context);
+            for (AltTarget altTarget : this.altTargets) {
+                String useWhen = FlexibleStringExpander.expandString(altTarget.useWhen, context);
+                Object retVal = bsh.eval(StringUtil.convertOperatorSubstitutions(useWhen));
+                boolean condTrue = false;
+                // retVal should be a Boolean, if not something weird is up...
+                if (retVal instanceof Boolean) {
+                    Boolean boolVal = (Boolean) retVal;
+                    condTrue = boolVal.booleanValue();
+                } else {
+                    throw new IllegalArgumentException("Return value from target condition eval was not a Boolean: "
+                            + retVal.getClass().getName() + " [" + retVal + "] of form " + getName());
+                }
+
+                if (condTrue && !targetType.equals("inter-app")) {
+                    return altTarget.targetExdr.expandString(expanderContext);
+                }
+            }
+        } catch (EvalError e) {
+            String errmsg = "Error evaluating BeanShell target conditions on form " + getName();
+            Debug.logError(e, errmsg, module);
+            throw new IllegalArgumentException(errmsg);
+        }
+        return target.expandString(expanderContext);
+    }
+
+    public String getTargetType() {
+        return this.targetType;
+    }
+
+    public String getTargetWindow() {
+        return targetWindowExdr.getOriginal();
+    }
+
+    public String getTargetWindow(Map<String, Object> context) {
+        return this.targetWindowExdr.expandString(context);
+    }
+
+    public String getTitle() {
+        return this.title;
+    }
+
+    public String getTooltip() {
+        return this.tooltip;
+    }
+
+    public String getType() {
+        return this.type;
+    }
+
+    public boolean getUseRowSubmit() {
+        return this.useRowSubmit;
+    }
+
+    public Set<String> getUseWhenFields() {
+        return useWhenFields;
+    }
+    public boolean getGroupColumns() {
+        return groupColumns;
+    }
+
+    public boolean isOverridenListSize() {
+        return !this.overrideListSize.isEmpty();
+    }
+
+    public void runFormActions(Map<String, Object> context) {
+        AbstractModelAction.runSubActions(this.actions, context);
+    }
+
+    public static class AltRowStyle {
+        public final String useWhen;
+        public final String style;
+
+        public AltRowStyle(Element altRowStyleElement) {
+            this.useWhen = altRowStyleElement.getAttribute("use-when");
+            this.style = altRowStyleElement.getAttribute("style");
+        }
+    }
+
+    public static class AltTarget {
+        public final String useWhen;
+        public final FlexibleStringExpander targetExdr;
+
+        public AltTarget(Element altTargetElement) {
+            this.useWhen = altTargetElement.getAttribute("use-when");
+            this.targetExdr = FlexibleStringExpander.getInstance(altTargetElement.getAttribute("target"));
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return obj instanceof AltTarget && obj.hashCode() == this.hashCode();
+        }
+
+        @Override
+        public int hashCode() {
+            return useWhen.hashCode();
+        }
+    }
+
+    public static class AutoFieldsEntity {
+        public final String entityName;
+        public final String mapName;
+        public final String defaultFieldType;
+        public final int defaultPosition;
+
+        public AutoFieldsEntity(Element element) {
+            this.entityName = element.getAttribute("entity-name");
+            this.mapName = element.getAttribute("map-name");
+            this.defaultFieldType = element.getAttribute("default-field-type");
+            String positionStr = element.getAttribute("default-position");
+            int position = 1;
+            try {
+                if (UtilValidate.isNotEmpty(positionStr)) {
+                    position = Integer.valueOf(positionStr);
+                }
+            } catch (Exception e) {
+                Debug.logError(e, "Could not convert position attribute of the field element to an integer: [" + positionStr
+                        + "], using the default of the form renderer", module);
+            }
+            this.defaultPosition = position;
+        }
+    }
+
+    public static class AutoFieldsService {
+        public final String serviceName;
+        public final String mapName;
+        public final String defaultFieldType;
+        public final int defaultPosition;
+
+        public AutoFieldsService(Element element) {
+            this.serviceName = element.getAttribute("service-name");
+            this.mapName = element.getAttribute("map-name");
+            this.defaultFieldType = element.getAttribute("default-field-type");
+            String positionStr = element.getAttribute("default-position");
+            int position = 1;
+            try {
+                if (UtilValidate.isNotEmpty(positionStr)) {
+                    position = Integer.valueOf(positionStr);
+                }
+            } catch (Exception e) {
+                Debug.logError(e, "Could not convert position attribute of the field element to an integer: [" + positionStr
+                        + "], using the default of the form renderer", module);
+            }
+            this.defaultPosition = position;
+        }
+    }
+
+    public static class Banner implements FieldGroupBase {
+        public final FlexibleStringExpander style;
+        public final FlexibleStringExpander text;
+        public final FlexibleStringExpander textStyle;
+        public final FlexibleStringExpander leftText;
+        public final FlexibleStringExpander leftTextStyle;
+        public final FlexibleStringExpander rightText;
+        public final FlexibleStringExpander rightTextStyle;
+
+        public Banner(Element sortOrderElement) {
+            this.style = FlexibleStringExpander.getInstance(sortOrderElement.getAttribute("style"));
+            this.text = FlexibleStringExpander.getInstance(sortOrderElement.getAttribute("text"));
+            this.textStyle = FlexibleStringExpander.getInstance(sortOrderElement.getAttribute("text-style"));
+            this.leftText = FlexibleStringExpander.getInstance(sortOrderElement.getAttribute("left-text"));
+            this.leftTextStyle = FlexibleStringExpander.getInstance(sortOrderElement.getAttribute("left-text-style"));
+            this.rightText = FlexibleStringExpander.getInstance(sortOrderElement.getAttribute("right-text"));
+            this.rightTextStyle = FlexibleStringExpander.getInstance(sortOrderElement.getAttribute("right-text-style"));
+        }
+
+        public String getLeftText(Map<String, Object> context) {
+            return this.leftText.expandString(context);
+        }
+
+        public String getLeftTextStyle(Map<String, Object> context) {
+            return this.leftTextStyle.expandString(context);
+        }
+
+        public String getRightText(Map<String, Object> context) {
+            return this.rightText.expandString(context);
+        }
+
+        public String getRightTextStyle(Map<String, Object> context) {
+            return this.rightTextStyle.expandString(context);
+        }
+
+        public String getStyle(Map<String, Object> context) {
+            return this.style.expandString(context);
+        }
+
+        public String getText(Map<String, Object> context) {
+            return this.text.expandString(context);
+        }
+
+        public String getTextStyle(Map<String, Object> context) {
+            return this.textStyle.expandString(context);
+        }
+
+        public void renderString(Appendable writer, Map<String, Object> context, FormStringRenderer formStringRenderer)
+                throws IOException {
+            formStringRenderer.renderBanner(writer, context, this);
+        }
+    }
+
+    public static class FieldGroup implements FieldGroupBase {
+        private static AtomicInteger baseSeqNo = new AtomicInteger(0);
+        private static final String baseId = "_G";
+        private final String id;
+        private final String style;
+        private final String title;
+        private final boolean collapsible;
+        private final boolean initiallyCollapsed;
+        private final ModelForm modelForm;
+
+        public FieldGroup(Element sortOrderElement, ModelForm modelForm, List<SortField> sortOrderFields,
+                Map<String, FieldGroupBase> fieldGroupMap) {
+            this.modelForm = modelForm;
+            String id;
+            String style = "";
+            String title = "";
+            boolean collapsible = false;
+            boolean initiallyCollapsed = false;
+            if (sortOrderElement != null) {
+                id = sortOrderElement.getAttribute("id");
+                if (id.isEmpty()) {
+                    String lastGroupId = baseId + baseSeqNo.getAndIncrement() + "_";
+                    id = lastGroupId;
+                }
+                style = sortOrderElement.getAttribute("style");
+                title = sortOrderElement.getAttribute("title");
+                collapsible = "true".equals(sortOrderElement.getAttribute("collapsible"));
+                initiallyCollapsed = "true".equals(sortOrderElement.getAttribute("initially-collapsed"));
+                if (initiallyCollapsed) {
+                    collapsible = true;
+                }
+                for (Element sortFieldElement : UtilXml.childElementList(sortOrderElement, "sort-field")) {
+                    sortOrderFields.add(new SortField(sortFieldElement.getAttribute("name"), sortFieldElement
+                            .getAttribute("position")));
+                    fieldGroupMap.put(sortFieldElement.getAttribute("name"), this);
+                }
+            } else {
+                String lastGroupId = baseId + baseSeqNo.getAndIncrement() + "_";
+                id = lastGroupId;
+            }
+            this.id = id;
+            this.style = style;
+            this.title = title;
+            this.collapsible = collapsible;
+            this.initiallyCollapsed = initiallyCollapsed;
+        }
+
+        public Boolean collapsible() {
+            return this.collapsible;
+        }
+
+        public String getId() {
+            return this.id;
+        }
+
+        public String getStyle() {
+            return this.style;
+        }
+
+        public String getTitle() {
+            return this.title;
+        }
+
+        public Boolean initiallyCollapsed() {
+            return this.initiallyCollapsed;
+        }
+
+        public void renderEndString(Appendable writer, Map<String, Object> context, FormStringRenderer formStringRenderer)
+                throws IOException {
+            formStringRenderer.renderFormatSingleWrapperClose(writer, context, modelForm);
+            if (!modelForm.fieldGroupList.isEmpty()) {
+                if (shouldUse(context)) {
+                    formStringRenderer.renderFieldGroupClose(writer, context, this);
+                }
+            }
+        }
+
+        public void renderStartString(Appendable writer, Map<String, Object> context, FormStringRenderer formStringRenderer)
+                throws IOException {
+            if (!modelForm.fieldGroupList.isEmpty()) {
+                if (shouldUse(context)) {
+                    formStringRenderer.renderFieldGroupOpen(writer, context, this);
+                }
+            }
+            formStringRenderer.renderFormatSingleWrapperOpen(writer, context, modelForm);
+        }
+
+        public boolean shouldUse(Map<String, Object> context) {
+            for (String fieldName : modelForm.fieldGroupMap.keySet()) {
+                FieldGroupBase group = modelForm.fieldGroupMap.get(fieldName);
+                if (group instanceof FieldGroup) {
+                    FieldGroup fieldgroup = (FieldGroup) group;
+                    if (this.id.equals(fieldgroup.getId())) {
+                        for (ModelFormField modelField : modelForm.fieldList) {
+                            if (fieldName.equals(modelField.getName()) && modelField.shouldUse(context)) {
+                                return true;
+                            }
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+    }
+
+    public static interface FieldGroupBase {
+    }
+
+    public static class SortField {
+        private final String fieldName;
+        private final Integer position;
+
+        public SortField(String name) {
+            this(name, null);
+        }
+
+        public SortField(String name, String position) {
+            this.fieldName = name;
+            if (UtilValidate.isNotEmpty(position)) {
+                Integer posParam = null;
+                try {
+                    posParam = Integer.valueOf(position);
+                } catch (Exception e) {/* just ignore the exception*/
+                }
+                this.position = posParam;
+            } else {
+                this.position = null;
+            }
+        }
+
+        public String getFieldName() {
+            return this.fieldName;
+        }
+
+        public Integer getPosition() {
+            return this.position;
+        }
+    }
+
+    /** The UpdateArea class implements the <code>&lt;on-event-update-area&gt;</code>
+     * elements used in form widgets.
+     */
+    public static class UpdateArea {
+        private final String eventType;
+        private final String areaId;
+        private final String areaTarget;
+        private final String defaultServiceName;
+        private final String defaultEntityName;
+        private final CommonWidgetModels.AutoEntityParameters autoEntityParameters;
+        private final CommonWidgetModels.AutoServiceParameters autoServiceParameters;
+        private final List<CommonWidgetModels.Parameter> parameterList;
+
+        public UpdateArea(Element updateAreaElement) {
+            this(updateAreaElement, null, null);
+        }
+
+        /** XML constructor.
+         * @param updateAreaElement The <code>&lt;on-xxx-update-area&gt;</code>
+         * XML element.
+         */
+        public UpdateArea(Element updateAreaElement, String defaultServiceName, String defaultEntityName) {
+            this.eventType = updateAreaElement.getAttribute("event-type");
+            this.areaId = updateAreaElement.getAttribute("area-id");
+            this.areaTarget = updateAreaElement.getAttribute("area-target");
+            this.defaultServiceName = defaultServiceName;
+            this.defaultEntityName = defaultEntityName;
+            List<? extends Element> parameterElementList = UtilXml.childElementList(updateAreaElement, "parameter");
+            if (parameterElementList.isEmpty()) {
+                this.parameterList = Collections.emptyList();
+            } else {
+                List<CommonWidgetModels.Parameter> parameterList = new ArrayList<CommonWidgetModels.Parameter>(parameterElementList.size());
+                for (Element parameterElement : parameterElementList) {
+                    parameterList.add(new CommonWidgetModels.Parameter(parameterElement));
+                }
+                this.parameterList = Collections.unmodifiableList(parameterList);
+            }
+            Element autoServiceParamsElement = UtilXml.firstChildElement(updateAreaElement, "auto-parameters-service");
+            if (autoServiceParamsElement != null) {
+                this.autoServiceParameters = new CommonWidgetModels.AutoServiceParameters(autoServiceParamsElement);
+            } else {
+                this.autoServiceParameters = null;
+            }
+            Element autoEntityParamsElement = UtilXml.firstChildElement(updateAreaElement, "auto-parameters-entity");
+            if (autoEntityParamsElement != null) {
+                this.autoEntityParameters = new CommonWidgetModels.AutoEntityParameters(autoEntityParamsElement);
+            } else {
+                this.autoEntityParameters = null;
+            }
+        }
+
+        /** String constructor.
+         * @param areaId The id of the widget element to be updated
+         * @param areaTarget The target URL called to update the area
+         */
+        public UpdateArea(String eventType, String areaId, String areaTarget) {
+            this.eventType = eventType;
+            this.areaId = areaId;
+            this.areaTarget = areaTarget;
+            this.defaultServiceName = null;
+            this.defaultEntityName = null;
+            this.parameterList = Collections.emptyList();
+            this.autoServiceParameters = null;
+            this.autoEntityParameters = null;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return obj instanceof UpdateArea && obj.hashCode() == this.hashCode();
+        }
+
+        public String getAreaId() {
+            return areaId;
+        }
+
+        public String getAreaTarget(Map<String, ? extends Object> context) {
+            return FlexibleStringExpander.expandString(areaTarget, context);
+        }
+
+        public String getEventType() {
+            return eventType;
+        }
+
+        public Map<String, String> getParameterMap(Map<String, Object> context) {
+            Map<String, String> fullParameterMap = new HashMap<String, String>();
+            if (autoServiceParameters != null) {
+                fullParameterMap.putAll(autoServiceParameters.getParametersMap(context, defaultServiceName));
+            }
+            if (autoEntityParameters != null) {
+                fullParameterMap.putAll(autoEntityParameters.getParametersMap(context, defaultEntityName));
+            }
+            for (CommonWidgetModels.Parameter parameter : this.parameterList) {
+                fullParameterMap.put(parameter.getName(), parameter.getValue(context));
+            }
+
+            return fullParameterMap;
+        }
+
+        @Override
+        public int hashCode() {
+            return areaId.hashCode();
+        }
+
+        public String getAreaTarget() {
+            return areaTarget;
+        }
+
+        public String getDefaultServiceName() {
+            return defaultServiceName;
+        }
+
+        public String getDefaultEntityName() {
+            return defaultEntityName;
+        }
+
+        public CommonWidgetModels.AutoEntityParameters getAutoEntityParameters() {
+            return autoEntityParameters;
+        }
+
+        public CommonWidgetModels.AutoServiceParameters getAutoServiceParameters() {
+            return autoServiceParameters;
+        }
+
+        public List<CommonWidgetModels.Parameter> getParameterList() {
+            return parameterList;
+        }
+    }
+}