/******************************************************************************* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. *******************************************************************************/ package org.apache.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.codehaus.groovy.control.CompilationFailedException; import org.apache.ofbiz.base.util.Debug; import org.apache.ofbiz.base.util.GroovyUtil; import org.apache.ofbiz.base.util.StringUtil; import org.apache.ofbiz.base.util.UtilCodec; import org.apache.ofbiz.base.util.UtilGenerics; import org.apache.ofbiz.base.util.UtilProperties; import org.apache.ofbiz.base.util.UtilValidate; import org.apache.ofbiz.base.util.UtilXml; import org.apache.ofbiz.base.util.collections.FlexibleMapAccessor; import org.apache.ofbiz.base.util.string.FlexibleStringExpander; import org.apache.ofbiz.entity.GenericEntityException; import org.apache.ofbiz.entity.model.ModelEntity; import org.apache.ofbiz.entity.model.ModelField; import org.apache.ofbiz.entity.model.ModelReader; import org.apache.ofbiz.service.DispatchContext; import org.apache.ofbiz.service.GenericServiceException; import org.apache.ofbiz.service.ModelParam; import org.apache.ofbiz.service.ModelService; import org.apache.ofbiz.widget.WidgetWorker; import org.apache.ofbiz.widget.renderer.FormStringRenderer; import org.w3c.dom.Element; /** * Abstract base class for the <form> and <grid> elements. * * @see <code>widget-form.xsd</code> */ @SuppressWarnings("serial") public abstract 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 parentModel; 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 */ protected ModelForm(Element formElement, String formLocation, ModelReader entityModelReader, DispatchContext dispatchContext, String defaultType) { super(formElement); this.formLocation = formLocation; parentModel = getParentModel(formElement, entityModelReader, dispatchContext); int defaultViewSizeInt = DEFAULT_PAGE_SIZE; String viewSize = formElement.getAttribute("view-size"); if (viewSize.isEmpty()) { if (parentModel != null) { defaultViewSizeInt = parentModel.defaultViewSize; } else { defaultViewSizeInt = UtilProperties.getPropertyAsInteger("widget", "widget.form.defaultViewSize", defaultViewSizeInt); } } else { try { defaultViewSizeInt = Integer.valueOf(viewSize); } catch (NumberFormatException e) { } } this.defaultViewSize = defaultViewSizeInt; String type = formElement.getAttribute("type"); if (type.isEmpty()) { if (parentModel != null) { type = parentModel.type; } else { type = defaultType; } } this.type = type; FlexibleStringExpander target = FlexibleStringExpander.getInstance(formElement.getAttribute("target")); if (target.isEmpty() && parentModel != null) { target = parentModel.target; } this.target = target; String containerId = formElement.getAttribute("id"); if (containerId.isEmpty() && parentModel != null) { containerId = parentModel.containerId; } this.containerId = containerId; String containerStyle = formElement.getAttribute("style"); if (containerStyle.isEmpty() && parentModel != null) { containerStyle = parentModel.containerStyle; } this.containerStyle = containerStyle; String title = formElement.getAttribute("title"); if (title.isEmpty() && parentModel != null) { title = parentModel.title; } this.title = title; String tooltip = formElement.getAttribute("tooltip"); if (tooltip.isEmpty() && parentModel != null) { tooltip = parentModel.tooltip; } this.tooltip = tooltip; String listName = formElement.getAttribute("list-name"); if (listName.isEmpty()) { if (parentModel != null) { listName = parentModel.listName; } else { listName = DEFAULT_FORM_RESULT_LIST_NAME; } } this.listName = listName; String listEntryName = formElement.getAttribute("list-entry-name"); if (listEntryName.isEmpty() && parentModel != null) { listEntryName = parentModel.listEntryName; } this.listEntryName = listEntryName; String defaultEntityName = formElement.getAttribute("default-entity-name"); if (defaultEntityName.isEmpty() && parentModel != null) { defaultEntityName = parentModel.defaultEntityName; } this.defaultEntityName = defaultEntityName; String defaultServiceName = formElement.getAttribute("default-service-name"); if (defaultServiceName.isEmpty() && parentModel != null) { defaultServiceName = parentModel.defaultServiceName; } this.defaultServiceName = defaultServiceName; String formTitleAreaStyle = formElement.getAttribute("form-title-area-style"); if (formTitleAreaStyle.isEmpty() && parentModel != null) { formTitleAreaStyle = parentModel.formTitleAreaStyle; } this.formTitleAreaStyle = formTitleAreaStyle; String formWidgetAreaStyle = formElement.getAttribute("form-widget-area-style"); if (formWidgetAreaStyle.isEmpty() && parentModel != null) { formWidgetAreaStyle = parentModel.formWidgetAreaStyle; } this.formWidgetAreaStyle = formWidgetAreaStyle; String defaultTitleAreaStyle = formElement.getAttribute("default-title-area-style"); if (defaultTitleAreaStyle.isEmpty() && parentModel != null) { defaultTitleAreaStyle = parentModel.defaultTitleAreaStyle; } this.defaultTitleAreaStyle = defaultTitleAreaStyle; String defaultWidgetAreaStyle = formElement.getAttribute("default-widget-area-style"); if (defaultWidgetAreaStyle.isEmpty() && parentModel != null) { defaultWidgetAreaStyle = parentModel.defaultWidgetAreaStyle; } this.defaultWidgetAreaStyle = defaultWidgetAreaStyle; String oddRowStyle = formElement.getAttribute("odd-row-style"); if (oddRowStyle.isEmpty() && parentModel != null) { oddRowStyle = parentModel.oddRowStyle; } this.oddRowStyle = oddRowStyle; String evenRowStyle = formElement.getAttribute("even-row-style"); if (evenRowStyle.isEmpty() && parentModel != null) { evenRowStyle = parentModel.evenRowStyle; } this.evenRowStyle = evenRowStyle; String defaultTableStyle = formElement.getAttribute("default-table-style"); if (defaultTableStyle.isEmpty() && parentModel != null) { defaultTableStyle = parentModel.defaultTableStyle; } this.defaultTableStyle = defaultTableStyle; String headerRowStyle = formElement.getAttribute("header-row-style"); if (headerRowStyle.isEmpty() && parentModel != null) { headerRowStyle = parentModel.headerRowStyle; } this.headerRowStyle = headerRowStyle; String defaultTitleStyle = formElement.getAttribute("default-title-style"); if (defaultTitleStyle.isEmpty() && parentModel != null) { defaultTitleStyle = parentModel.defaultTitleStyle; } this.defaultTitleStyle = defaultTitleStyle; String defaultWidgetStyle = formElement.getAttribute("default-widget-style"); if (defaultWidgetStyle.isEmpty() && parentModel != null) { defaultWidgetStyle = parentModel.defaultWidgetStyle; } this.defaultWidgetStyle = defaultWidgetStyle; String defaultTooltipStyle = formElement.getAttribute("default-tooltip-style"); if (defaultTooltipStyle.isEmpty() && parentModel != null) { defaultTooltipStyle = parentModel.defaultTooltipStyle; } this.defaultTooltipStyle = defaultTooltipStyle; String itemIndexSeparator = formElement.getAttribute("item-index-separator"); if (itemIndexSeparator.isEmpty() && parentModel != null) { itemIndexSeparator = parentModel.itemIndexSeparator; } this.itemIndexSeparator = itemIndexSeparator; String separateColumns = formElement.getAttribute("separate-columns"); if (separateColumns.isEmpty() && parentModel != null) { this.separateColumns = parentModel.separateColumns; } else { this.separateColumns = "true".equals(separateColumns); } String groupColumns = formElement.getAttribute("group-columns"); if (groupColumns.isEmpty() && parentModel != null) { this.groupColumns = parentModel.groupColumns; } else { this.groupColumns = !"false".equals(groupColumns); } String targetType = formElement.getAttribute("target-type"); if (targetType.isEmpty() && parentModel != null) { targetType = parentModel.targetType; } this.targetType = targetType; FlexibleMapAccessor<Map<String, ? extends Object>> defaultMapName = FlexibleMapAccessor.getInstance(formElement .getAttribute("default-map-name")); if (defaultMapName.isEmpty() && parentModel != null) { defaultMapName = parentModel.defaultMapName; } this.defaultMapName = defaultMapName; FlexibleStringExpander targetWindowExdr = FlexibleStringExpander.getInstance(formElement.getAttribute("target-window")); if (targetWindowExdr.isEmpty() && parentModel != null) { targetWindowExdr = parentModel.targetWindowExdr; } this.targetWindowExdr = targetWindowExdr; String hideHeader = formElement.getAttribute("hide-header"); if (hideHeader.isEmpty() && parentModel != null) { this.hideHeader = parentModel.hideHeader; } else { this.hideHeader = "true".equals(hideHeader); } String clientAutocompleteFields = formElement.getAttribute("client-autocomplete-fields"); if (clientAutocompleteFields.isEmpty() && parentModel != null) { this.clientAutocompleteFields = parentModel.clientAutocompleteFields; } else { this.clientAutocompleteFields = !"false".equals(formElement.getAttribute("client-autocomplete-fields")); } FlexibleStringExpander paginateTarget = FlexibleStringExpander.getInstance(formElement.getAttribute("paginate-target")); if (paginateTarget.isEmpty() && parentModel != null) { paginateTarget = parentModel.paginateTarget; } this.paginateTarget = paginateTarget; ArrayList<AltTarget> altTargets = new ArrayList<AltTarget>(); for (Element altTargetElement : UtilXml.childElementList(formElement, "alt-target")) { altTargets.add(new AltTarget(altTargetElement)); } if (parentModel != null) { altTargets.addAll(parentModel.altTargets); } altTargets.trimToSize(); this.altTargets = Collections.unmodifiableList(altTargets); ArrayList<ModelAction> actions = new ArrayList<ModelAction>(); if (parentModel != null) { actions.addAll(parentModel.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 (parentModel != null) { rowActions.addAll(parentModel.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 (parentModel != null) { onPaginateUpdateAreas.addAll(parentModel.onPaginateUpdateAreas); onSubmitUpdateAreas.addAll(parentModel.onSubmitUpdateAreas); onSortColumnUpdateAreas.addAll(parentModel.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 (parentModel != null) { altRowStyles.addAll(parentModel.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 (parentModel != null) { useWhenFields.addAll(parentModel.useWhenFields); } List<ModelFormFieldBuilder> fieldBuilderList = new ArrayList<ModelFormFieldBuilder>(); Map<String, ModelFormFieldBuilder> fieldBuilderMap = new HashMap<String, ModelFormFieldBuilder>(); if (parentModel != null) { // Create this fieldList/Map from clones of parentModel's for (ModelFormField parentChildField : parentModel.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 (parentModel != null) { fieldGroupMap.putAll(parentModel.fieldGroupMap); } ArrayList<FieldGroupBase> fieldGroupList = new ArrayList<FieldGroupBase>(); if (parentModel != null) { fieldGroupList.addAll(parentModel.fieldGroupList); } ArrayList<String> lastOrderFields = new ArrayList<String>(); if (parentModel != null) { lastOrderFields.addAll(parentModel.lastOrderFields); } String sortFieldParameterName = formElement.getAttribute("sort-field-parameter-name"); if (sortFieldParameterName.isEmpty() && parentModel != null) { this.sortFieldParameterName = parentModel.targetType; } else { this.sortFieldParameterName = "sortField"; } String defaultRequiredFieldStyle = formElement.getAttribute("default-required-field-style"); if (defaultRequiredFieldStyle.isEmpty() && parentModel != null) { defaultRequiredFieldStyle = parentModel.defaultRequiredFieldStyle; } this.defaultRequiredFieldStyle = defaultRequiredFieldStyle; String defaultSortFieldStyle = formElement.getAttribute("default-sort-field-style"); if (defaultSortFieldStyle.isEmpty() && parentModel != null) { this.defaultSortFieldStyle = parentModel.defaultSortFieldStyle; } else { this.defaultSortFieldStyle = DEFAULT_SORT_FIELD_STYLE; } String defaultSortFieldAscStyle = formElement.getAttribute("default-sort-field-asc-style"); if (defaultSortFieldAscStyle.isEmpty() && parentModel != null) { this.defaultSortFieldAscStyle = parentModel.defaultSortFieldAscStyle; } else { this.defaultSortFieldAscStyle = DEFAULT_SORT_FIELD_ASC_STYLE; } String defaultSortFieldDescStyle = formElement.getAttribute("default-sort-field-desc-style"); if (defaultSortFieldDescStyle.isEmpty() && parentModel != null) { this.defaultSortFieldDescStyle = parentModel.defaultSortFieldDescStyle; } else { this.defaultSortFieldDescStyle = DEFAULT_SORT_FIELD_DESC_STYLE; } String paginateTargetAnchor = formElement.getAttribute("paginate-target-anchor"); if (paginateTargetAnchor.isEmpty() && parentModel != null) { paginateTargetAnchor = parentModel.paginateTargetAnchor; } this.paginateTargetAnchor = paginateTargetAnchor; FlexibleStringExpander paginateIndexField = FlexibleStringExpander.getInstance(formElement .getAttribute("paginate-index-field")); if (paginateIndexField.isEmpty() && parentModel != null) { paginateIndexField = parentModel.paginateIndexField; } this.paginateIndexField = paginateIndexField; FlexibleStringExpander paginateSizeField = FlexibleStringExpander.getInstance(formElement .getAttribute("paginate-size-field")); if (paginateSizeField.isEmpty() && parentModel != null) { paginateSizeField = parentModel.paginateSizeField; } this.paginateSizeField = paginateSizeField; FlexibleStringExpander overrideListSize = FlexibleStringExpander.getInstance(formElement .getAttribute("override-list-size")); if (overrideListSize.isEmpty() && parentModel != null) { overrideListSize = parentModel.overrideListSize; } this.overrideListSize = overrideListSize; FlexibleStringExpander paginateFirstLabel = FlexibleStringExpander.getInstance(formElement .getAttribute("paginate-first-label")); if (paginateFirstLabel.isEmpty() && parentModel != null) { paginateFirstLabel = parentModel.paginateFirstLabel; } this.paginateFirstLabel = paginateFirstLabel; FlexibleStringExpander paginatePreviousLabel = FlexibleStringExpander.getInstance(formElement .getAttribute("paginate-previous-label")); if (paginatePreviousLabel.isEmpty() && parentModel != null) { paginatePreviousLabel = parentModel.paginatePreviousLabel; } this.paginatePreviousLabel = paginatePreviousLabel; FlexibleStringExpander paginateNextLabel = FlexibleStringExpander.getInstance(formElement .getAttribute("paginate-next-label")); if (paginateNextLabel.isEmpty() && parentModel != null) { paginateNextLabel = parentModel.paginateNextLabel; } this.paginateNextLabel = paginateNextLabel; FlexibleStringExpander paginateLastLabel = FlexibleStringExpander.getInstance(formElement .getAttribute("paginate-last-label")); if (paginateLastLabel.isEmpty() && parentModel != null) { paginateLastLabel = parentModel.paginateLastLabel; } this.paginateLastLabel = paginateLastLabel; FlexibleStringExpander paginateViewSizeLabel = FlexibleStringExpander.getInstance(formElement .getAttribute("paginate-viewsize-label")); if (paginateViewSizeLabel.isEmpty() && parentModel != null) { paginateViewSizeLabel = parentModel.paginateViewSizeLabel; } this.paginateViewSizeLabel = paginateViewSizeLabel; String paginateStyle = formElement.getAttribute("paginate-style"); if (paginateStyle.isEmpty()) { if(parentModel != null) { this.paginateStyle = parentModel.paginateStyle; } else { this.paginateStyle = DEFAULT_PAG_STYLE; } } else { this.paginateStyle = paginateStyle; } FlexibleStringExpander paginate = FlexibleStringExpander.getInstance(formElement.getAttribute("paginate")); if (paginate.isEmpty() && parentModel != null) { paginate = parentModel.paginate; } this.paginate = paginate; String skipStart = formElement.getAttribute("skip-start"); if (skipStart.isEmpty() && parentModel != null) { this.skipStart = parentModel.skipStart; } else { this.skipStart = "true".equals(skipStart); } String skipEnd = formElement.getAttribute("skip-end"); if (skipEnd.isEmpty() && parentModel != null) { this.skipEnd = parentModel.skipEnd; } else { this.skipEnd = "true".equals(skipEnd); } String useRowSubmit = formElement.getAttribute("use-row-submit"); if (useRowSubmit.isEmpty() && parentModel != null) { this.useRowSubmit = parentModel.useRowSubmit; } else { this.useRowSubmit = "true".equals(useRowSubmit); } FlexibleStringExpander rowCountExdr = FlexibleStringExpander.getInstance(formElement.getAttribute("row-count")); if (rowCountExdr.isEmpty() && parentModel != null) { rowCountExdr = parentModel.rowCountExdr; } this.rowCountExdr = paginate; List<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) { List<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() && parentModel != null) { focusFieldName = parentModel.focusFieldName; } this.focusFieldName = focusFieldName; } 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; } @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.]", ""); if (!size.isEmpty()) { 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; } protected abstract ModelForm getParentModel(Element formElement, ModelReader entityModelReader, DispatchContext dispatchContext); public String getParentFormLocation() { return this.parentModel == null ? null : this.parentModel.getFormLocation(); } public String getParentFormName() { return this.parentModel == null ? null : this.parentModel.getName(); } public ModelForm getParentModelForm() { return parentModel; } 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 { for (AltRowStyle altRowStyle : this.altRowStyles) { Object retVal = GroovyUtil.eval(StringUtil.convertOperatorSubstitutions(altRowStyle.useWhen),context); // 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 (CompilationFailedException e) { String errmsg = "Error evaluating groovy 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 { for (AltTarget altTarget : this.altTargets) { String useWhen = FlexibleStringExpander.expandString(altTarget.useWhen, context); Object retVal = GroovyUtil.eval(StringUtil.convertOperatorSubstitutions(useWhen),context); 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 (CompilationFailedException e) { String errmsg = "Error evaluating Groovy 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><on-event-update-area></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><on-xxx-update-area></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; } } }