Java tutorial
/** * Copyright 2005-2014 The Kuali Foundation * * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php * * 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.kuali.rice.kns.util; import java.lang.reflect.InvocationTargetException; import java.security.GeneralSecurityException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.commons.beanutils.NestedNullException; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.lang.StringUtils; import org.kuali.rice.core.api.CoreApiServiceLocator; import org.kuali.rice.core.api.data.DataType; import org.kuali.rice.core.api.encryption.EncryptionService; import org.kuali.rice.core.api.mo.common.active.MutableInactivatable; import org.kuali.rice.core.api.uif.AttributeLookupSettings; import org.kuali.rice.core.api.uif.RemotableAbstractControl; import org.kuali.rice.core.api.uif.RemotableAbstractWidget; import org.kuali.rice.core.api.uif.RemotableAttributeField; import org.kuali.rice.core.api.uif.RemotableAttributeLookupSettings; import org.kuali.rice.core.api.uif.RemotableCheckbox; import org.kuali.rice.core.api.uif.RemotableCheckboxGroup; import org.kuali.rice.core.api.uif.RemotableControlContract; import org.kuali.rice.core.api.uif.RemotableDatepicker; import org.kuali.rice.core.api.uif.RemotableHiddenInput; import org.kuali.rice.core.api.uif.RemotablePasswordInput; import org.kuali.rice.core.api.uif.RemotableQuickFinder; import org.kuali.rice.core.api.uif.RemotableRadioButtonGroup; import org.kuali.rice.core.api.uif.RemotableSelect; import org.kuali.rice.core.api.uif.RemotableTextExpand; import org.kuali.rice.core.api.uif.RemotableTextInput; import org.kuali.rice.core.api.uif.RemotableTextarea; import org.kuali.rice.core.api.util.ClassLoaderUtils; import org.kuali.rice.core.api.util.ConcreteKeyValue; import org.kuali.rice.core.api.util.KeyValue; import org.kuali.rice.core.api.util.io.SerializationUtils; import org.kuali.rice.core.web.format.FormatException; import org.kuali.rice.core.web.format.Formatter; import org.kuali.rice.kew.api.KewApiConstants; import org.kuali.rice.kim.api.identity.Person; import org.kuali.rice.kns.datadictionary.BusinessObjectEntry; import org.kuali.rice.kns.datadictionary.FieldDefinition; import org.kuali.rice.kns.datadictionary.MaintainableCollectionDefinition; import org.kuali.rice.kns.datadictionary.control.ButtonControlDefinition; import org.kuali.rice.kns.datadictionary.control.CurrencyControlDefinition; import org.kuali.rice.kns.datadictionary.control.KualiUserControlDefinition; import org.kuali.rice.kns.datadictionary.control.LinkControlDefinition; import org.kuali.rice.kns.document.authorization.FieldRestriction; import org.kuali.rice.kns.document.authorization.MaintenanceDocumentRestrictions; import org.kuali.rice.kns.inquiry.Inquirable; import org.kuali.rice.kns.lookup.HtmlData; import org.kuali.rice.kns.lookup.HtmlData.AnchorHtmlData; import org.kuali.rice.kns.lookup.LookupUtils; import org.kuali.rice.kns.service.BusinessObjectDictionaryService; import org.kuali.rice.kns.service.BusinessObjectMetaDataService; import org.kuali.rice.kns.service.KNSServiceLocator; import org.kuali.rice.kns.web.comparator.CellComparatorHelper; import org.kuali.rice.kns.web.ui.Column; import org.kuali.rice.kns.web.ui.Field; import org.kuali.rice.kns.web.ui.PropertyRenderingConfigElement; import org.kuali.rice.kns.web.ui.Row; import org.kuali.rice.kns.web.ui.Section; import org.kuali.rice.krad.bo.BusinessObject; import org.kuali.rice.krad.bo.DataObjectRelationship; import org.kuali.rice.krad.bo.KualiCode; import org.kuali.rice.krad.bo.PersistableBusinessObject; import org.kuali.rice.krad.datadictionary.control.ControlDefinition; import org.kuali.rice.krad.datadictionary.exception.UnknownBusinessClassAttributeException; import org.kuali.rice.krad.datadictionary.mask.MaskFormatter; import org.kuali.rice.krad.keyvalues.IndicatorValuesFinder; import org.kuali.rice.krad.keyvalues.KeyValuesFinder; import org.kuali.rice.krad.keyvalues.PersistableBusinessObjectValuesFinder; import org.kuali.rice.krad.service.DataDictionaryService; import org.kuali.rice.krad.service.KRADServiceLocatorWeb; import org.kuali.rice.krad.service.KualiModuleService; import org.kuali.rice.krad.service.ModuleService; import org.kuali.rice.krad.util.ExternalizableBusinessObjectUtils; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.KRADConstants; import org.kuali.rice.krad.util.KRADPropertyConstants; import org.kuali.rice.krad.util.MessageMap; import org.kuali.rice.krad.util.ObjectUtils; import org.kuali.rice.krad.valuefinder.ValueFinder; /** * This class is used to build Field objects from underlying data dictionary and general utility methods for handling fields. * * @deprecated Only used in KNS classes, use KRAD. */ @Deprecated public final class FieldUtils { private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(FieldUtils.class); private static DataDictionaryService dataDictionaryService = null; private static BusinessObjectMetaDataService businessObjectMetaDataService = null; private static BusinessObjectDictionaryService businessObjectDictionaryService = null; private static KualiModuleService kualiModuleService = null; private FieldUtils() { throw new UnsupportedOperationException("do not call"); } public static void setInquiryURL(Field field, BusinessObject bo, String propertyName) { HtmlData inquiryHref = new AnchorHtmlData(KRADConstants.EMPTY_STRING, KRADConstants.EMPTY_STRING); Boolean b = getBusinessObjectDictionaryService().noInquiryFieldInquiry(bo.getClass(), propertyName); if (b == null || !b.booleanValue()) { Class<Inquirable> inquirableClass = getBusinessObjectDictionaryService() .getInquirableClass(bo.getClass()); Boolean b2 = getBusinessObjectDictionaryService().forceLookupResultFieldInquiry(bo.getClass(), propertyName); Inquirable inq = null; try { if (inquirableClass != null) { inq = inquirableClass.newInstance(); } else { inq = KNSServiceLocator.getKualiInquirable(); if (LOG.isDebugEnabled()) { LOG.debug("Default Inquirable Class: " + inq.getClass()); } } inquiryHref = inq.getInquiryUrl(bo, propertyName, null == b2 ? false : b2.booleanValue()); } catch (Exception ex) { LOG.error("unable to create inquirable to get inquiry URL", ex); } } field.setInquiryURL(inquiryHref); } /** * Sets the control on the field based on the data dictionary definition * * @param businessObjectClass * - business object class for the field attribute * @param attributeName * - name of the attribute whose {@link Field} is being set * @param convertForLookup * - whether the field is being build for lookup search which impacts the control chosen * @param field * - {@link Field} to set control on */ public static void setFieldControl(Class businessObjectClass, String attributeName, boolean convertForLookup, Field field) { ControlDefinition control = getDataDictionaryService().getAttributeControlDefinition(businessObjectClass, attributeName); String fieldType = Field.TEXT; if (control != null) { if (control.isSelect()) { if (control.getScript() != null && control.getScript().length() > 0) { fieldType = Field.DROPDOWN_SCRIPT; field.setScript(control.getScript()); } else { fieldType = Field.DROPDOWN; } } if (control.isMultiselect()) { fieldType = Field.MULTISELECT; } if (control.isCheckbox()) { fieldType = Field.CHECKBOX; } if (control.isRadio()) { fieldType = Field.RADIO; } if (control.isHidden()) { fieldType = Field.HIDDEN; } if (control.isKualiUser()) { fieldType = Field.KUALIUSER; KualiUserControlDefinition kualiUserControl = (KualiUserControlDefinition) control; field.setUniversalIdAttributeName(kualiUserControl.getUniversalIdAttributeName()); field.setUserIdAttributeName(kualiUserControl.getUserIdAttributeName()); field.setPersonNameAttributeName(kualiUserControl.getPersonNameAttributeName()); } if (control.isWorkflowWorkgroup()) { fieldType = Field.WORKFLOW_WORKGROUP; } if (control.isFile()) { fieldType = Field.FILE; } if (control.isTextarea() && !convertForLookup) { fieldType = Field.TEXT_AREA; } if (control.isLookupHidden()) { fieldType = Field.LOOKUP_HIDDEN; } if (control.isLookupReadonly()) { fieldType = Field.LOOKUP_READONLY; } if (control.isCurrency()) { fieldType = Field.CURRENCY; } if (control.isButton()) { fieldType = Field.BUTTON; } if (control.isLink()) { fieldType = Field.LINK; } if (Field.CURRENCY.equals(fieldType) && control instanceof CurrencyControlDefinition) { CurrencyControlDefinition currencyControl = (CurrencyControlDefinition) control; field.setStyleClass("amount"); field.setSize(currencyControl.getSize()); field.setFormattedMaxLength(currencyControl.getFormattedMaxLength()); } // for text controls, set size attribute if (Field.TEXT.equals(fieldType)) { Integer size = control.getSize(); if (size != null) { field.setSize(size.intValue()); } else { field.setSize(30); } field.setDatePicker(control.isDatePicker()); field.setRanged(control.isRanged()); } if (Field.WORKFLOW_WORKGROUP.equals(fieldType)) { Integer size = control.getSize(); if (size != null) { field.setSize(size.intValue()); } else { field.setSize(30); } } // for text area controls, set rows and cols attributes if (Field.TEXT_AREA.equals(fieldType)) { Integer rows = control.getRows(); if (rows != null) { field.setRows(rows.intValue()); } else { field.setRows(3); } Integer cols = control.getCols(); if (cols != null) { field.setCols(cols.intValue()); } else { field.setCols(40); } field.setExpandedTextArea(control.isExpandedTextArea()); } if (Field.MULTISELECT.equals(fieldType)) { Integer size = control.getSize(); if (size != null) { field.setSize(size.intValue()); } } // for dropdown and radio, get instance of specified KeyValuesFinder and set field values if (Field.DROPDOWN.equals(fieldType) || Field.RADIO.equals(fieldType) || Field.DROPDOWN_SCRIPT.equals(fieldType) || Field.MULTISELECT.equals(fieldType)) { String keyFinderClassName = control.getValuesFinderClass(); if (StringUtils.isNotBlank(keyFinderClassName)) { try { Class keyFinderClass = ClassLoaderUtils.getClass(keyFinderClassName); KeyValuesFinder finder = (KeyValuesFinder) keyFinderClass.newInstance(); if (finder != null) { if (finder instanceof PersistableBusinessObjectValuesFinder) { ((PersistableBusinessObjectValuesFinder) finder).setBusinessObjectClass( ClassLoaderUtils.getClass(control.getBusinessObjectClass())); ((PersistableBusinessObjectValuesFinder) finder) .setKeyAttributeName(control.getKeyAttribute()); ((PersistableBusinessObjectValuesFinder) finder) .setLabelAttributeName(control.getLabelAttribute()); if (control.getIncludeBlankRow() != null) { ((PersistableBusinessObjectValuesFinder) finder) .setIncludeBlankRow(control.getIncludeBlankRow()); } ((PersistableBusinessObjectValuesFinder) finder) .setIncludeKeyInDescription(control.getIncludeKeyInLabel()); } field.setFieldValidValues(finder.getKeyValues()); field.setFieldInactiveValidValues(finder.getKeyValues(false)); } } catch (InstantiationException e) { LOG.error("Unable to get new instance of finder class: " + keyFinderClassName); throw new RuntimeException( "Unable to get new instance of finder class: " + keyFinderClassName); } catch (IllegalAccessException e) { LOG.error("Unable to get new instance of finder class: " + keyFinderClassName); throw new RuntimeException( "Unable to get new instance of finder class: " + keyFinderClassName); } } } if (Field.CHECKBOX.equals(fieldType) && convertForLookup) { fieldType = Field.RADIO; field.setFieldValidValues(IndicatorValuesFinder.INSTANCE.getKeyValues()); } // for button control if (Field.BUTTON.equals(fieldType)) { ButtonControlDefinition buttonControl = (ButtonControlDefinition) control; field.setImageSrc(buttonControl.getImageSrc()); field.setStyleClass(buttonControl.getStyleClass()); } // for link control if (Field.LINK.equals(fieldType)) { LinkControlDefinition linkControl = (LinkControlDefinition) control; field.setStyleClass(linkControl.getStyleClass()); field.setTarget(linkControl.getTarget()); field.setHrefText(linkControl.getHrefText()); } } field.setFieldType(fieldType); } /** * Builds up a Field object based on the propertyName and business object class. * * See KULRICE-2480 for info on convertForLookup flag * */ public static Field getPropertyField(Class businessObjectClass, String attributeName, boolean convertForLookup) { Field field = new Field(); field.setPropertyName(attributeName); //hack to get correct BO impl in case of ebos.... if (ExternalizableBusinessObjectUtils.isExternalizableBusinessObject(businessObjectClass)) { ModuleService moduleService = getKualiModuleService().getResponsibleModuleService(businessObjectClass); businessObjectClass = moduleService.getExternalizableBusinessObjectDictionaryEntry(businessObjectClass) .getDataObjectClass(); } field.setFieldLabel(getDataDictionaryService().getAttributeLabel(businessObjectClass, attributeName)); setFieldControl(businessObjectClass, attributeName, convertForLookup, field); Boolean fieldRequired = getBusinessObjectDictionaryService().getLookupAttributeRequired(businessObjectClass, attributeName); if (fieldRequired != null) { field.setFieldRequired(fieldRequired.booleanValue()); } Integer maxLength = getDataDictionaryService().getAttributeMaxLength(businessObjectClass, attributeName); if (maxLength != null) { field.setMaxLength(maxLength.intValue()); } Boolean upperCase = null; try { upperCase = getDataDictionaryService().getAttributeForceUppercase(businessObjectClass, attributeName); } catch (UnknownBusinessClassAttributeException t) { // do nothing LOG.warn("UnknownBusinessClassAttributeException in fieldUtils.getPropertyField() : " + t.getMessage()); } if (upperCase != null) { field.setUpperCase(upperCase.booleanValue()); } if (!businessObjectClass.isInterface()) { try { field.setFormatter(ObjectUtils.getFormatterWithDataDictionary(businessObjectClass.newInstance(), attributeName)); } catch (InstantiationException e) { LOG.info("Unable to get new instance of business object class: " + businessObjectClass.getName(), e); // just swallow exception and leave formatter blank } catch (IllegalAccessException e) { LOG.info("Unable to get new instance of business object class: " + businessObjectClass.getName(), e); // just swallow exception and leave formatter blank } } // set Field help properties field.setBusinessObjectClassName(businessObjectClass.getName()); field.setFieldHelpName(attributeName); field.setFieldHelpSummary( getDataDictionaryService().getAttributeSummary(businessObjectClass, attributeName)); return field; } /** * For attributes that are codes (determined by whether they have a * reference to a KualiCode bo and similar naming) sets the name as an * additional display property * * @param businessObjectClass - * class containing attribute * @param attributeName - * name of attribute in the business object * @param field - * property display element */ public static void setAdditionalDisplayPropertyForCodes(Class businessObjectClass, String attributeName, PropertyRenderingConfigElement field) { try { DataObjectRelationship relationship = getBusinessObjectMetaDataService().getBusinessObjectRelationship( (BusinessObject) businessObjectClass.newInstance(), attributeName); if (relationship != null && attributeName.startsWith(relationship.getParentAttributeName()) && KualiCode.class.isAssignableFrom(relationship.getRelatedClass())) { field.setAdditionalDisplayPropertyName( relationship.getParentAttributeName() + "." + KRADPropertyConstants.NAME); } } catch (Exception e) { throw new RuntimeException( "Cannot get new instance of class to check for KualiCode references: " + e.getMessage()); } } /** * Wraps each Field in the list into a Row. * * @param fields * @return List of Row objects */ public static List wrapFields(List fields) { return wrapFields(fields, KRADConstants.DEFAULT_NUM_OF_COLUMNS); } /** * This method is to implement multiple columns where the numberOfColumns is obtained from data dictionary. * * @param fields * @param numberOfColumns * @return */ public static List<Row> wrapFields(List<Field> fields, int numberOfColumns) { List<Row> rows = new ArrayList(); List<Field> fieldOnlyList = new ArrayList(); List<Field> visableFields = getVisibleFields(fields); List<Field> nonVisableFields = getNonVisibleFields(fields); int fieldsPosition = 0; for (Field element : visableFields) { if (Field.SUB_SECTION_SEPARATOR.equals(element.getFieldType()) || Field.CONTAINER.equals(element.getFieldType())) { fieldsPosition = createBlankSpace(fieldOnlyList, rows, numberOfColumns, fieldsPosition); List fieldList = new ArrayList(); fieldList.add(element); rows.add(new Row(fieldList)); } else { if (fieldsPosition < numberOfColumns) { fieldOnlyList.add(element); fieldsPosition++; } else { rows.add(new Row(new ArrayList(fieldOnlyList))); fieldOnlyList.clear(); fieldOnlyList.add(element); fieldsPosition = 1; } } } createBlankSpace(fieldOnlyList, rows, numberOfColumns, fieldsPosition); // Add back the non Visible Rows if (nonVisableFields != null && !nonVisableFields.isEmpty()) { Row nonVisRow = new Row(); nonVisRow.setFields(nonVisableFields); rows.add(nonVisRow); } return rows; } private static List<Field> getVisibleFields(List<Field> fields) { List<Field> rList = new ArrayList<Field>(); for (Field f : fields) { if (!Field.HIDDEN.equals(f.getFieldType()) && !Field.BLANK_SPACE.equals(f.getFieldType())) { rList.add(f); } } return rList; } private static List<Field> getNonVisibleFields(List<Field> fields) { List<Field> rList = new ArrayList<Field>(); for (Field f : fields) { if (Field.HIDDEN.equals(f.getFieldType()) || Field.BLANK_SPACE.equals(f.getFieldType())) { rList.add(f); } } return rList; } /** * This is a helper method to create and add a blank space to the fieldOnly List. * * @param fieldOnlyList * @param rows * @param numberOfColumns * @return fieldsPosition */ private static int createBlankSpace(List<Field> fieldOnlyList, List<Row> rows, int numberOfColumns, int fieldsPosition) { int fieldOnlySize = fieldOnlyList.size(); if (fieldOnlySize > 0) { for (int i = 0; i < (numberOfColumns - fieldOnlySize); i++) { Field empty = new Field(); empty.setFieldType(Field.BLANK_SPACE); // Must be set or AbstractLookupableHelperServiceImpl::preprocessDateFields dies empty.setPropertyName(Field.BLANK_SPACE); fieldOnlyList.add(empty); } rows.add(new Row(new ArrayList(fieldOnlyList))); fieldOnlyList.clear(); fieldsPosition = 0; } return fieldsPosition; } /** * Wraps list of fields into a Field of type CONTAINER * * @param name name for the field * @param label label for the field * @param fields list of fields that should be contained in the container * @return Field of type CONTAINER */ public static Field constructContainerField(String name, String label, List fields) { return constructContainerField(name, label, fields, KRADConstants.DEFAULT_NUM_OF_COLUMNS); } /** * Wraps list of fields into a Field of type CONTAINER and arrange them into multiple columns. * * @param name name for the field * @param label label for the field * @param fields list of fields that should be contained in the container * @param numberOfColumns the number of columns for each row that the fields should be arranged into * @return Field of type CONTAINER */ public static Field constructContainerField(String name, String label, List fields, int numberOfColumns) { Field containerField = new Field(); containerField.setPropertyName(name); containerField.setFieldLabel(label); containerField.setFieldType(Field.CONTAINER); containerField.setNumberOfColumnsForCollection(numberOfColumns); List rows = wrapFields(fields, numberOfColumns); containerField.setContainerRows(rows); return containerField; } /** * Uses reflection to get the property names of the business object, then checks for a matching field property name. If found, * takes the value of the business object property and populates the field value. Iterates through for all fields in the list. * * @param fields list of Field object to populate * @param bo business object to get field values from * @return List of fields with values populated from business object. */ public static List<Field> populateFieldsFromBusinessObject(List<Field> fields, BusinessObject bo) { List<Field> populatedFields = new ArrayList<Field>(); if (bo instanceof PersistableBusinessObject) { ((PersistableBusinessObject) bo).refreshNonUpdateableReferences(); } for (Iterator<Field> iter = fields.iterator(); iter.hasNext();) { Field element = iter.next(); if (element.containsBOData()) { String propertyName = element.getPropertyName(); // See: https://test.kuali.org/jira/browse/KULCOA-1185 // Properties that could not possibly be set by the BusinessObject should be ignored. // (https://test.kuali.org/jira/browse/KULRNE-4354; this code was killing the src attribute of IMAGE_SUBMITs). if (isPropertyNested(propertyName) && !isObjectTreeNonNullAllTheWayDown(bo, propertyName) && ((!element.getFieldType().equals(Field.IMAGE_SUBMIT)) && !(element.getFieldType().equals(Field.CONTAINER)) && (!element.getFieldType().equals(Field.QUICKFINDER)))) { element.setPropertyValue(null); } else if (isPropertyReadable(bo, propertyName)) { populateReadableField(element, bo); } if (StringUtils.isNotBlank(element.getAlternateDisplayPropertyName())) { String alternatePropertyValue = ObjectUtils.getFormattedPropertyValueUsingDataDictionary(bo, element.getAlternateDisplayPropertyName()); element.setAlternateDisplayPropertyValue(alternatePropertyValue); } if (StringUtils.isNotBlank(element.getAdditionalDisplayPropertyName())) { String additionalPropertyValue = ObjectUtils.getFormattedPropertyValueUsingDataDictionary(bo, element.getAdditionalDisplayPropertyName()); element.setAdditionalDisplayPropertyValue(additionalPropertyValue); } } populatedFields.add(element); } return populatedFields; } private static boolean isPropertyReadable(Object bean, String name) { try { return PropertyUtils.isReadable(bean, name); } catch (NestedNullException e) { return false; } } private static boolean isPropertyWritable(Object bean, String name) { try { return PropertyUtils.isWriteable(bean, name); } catch (NestedNullException e) { return false; } } public static void populateReadableField(Field field, BusinessObject businessObject) { Object obj = ObjectUtils.getNestedValue(businessObject, field.getPropertyName()); // For files the FormFile is not being persisted instead the file data is stored in // individual fields as defined by PersistableAttachment. if (Field.FILE.equals(field.getFieldType())) { Object fileName = ObjectUtils.getNestedValue(businessObject, KRADConstants.BO_ATTACHMENT_FILE_NAME); Object fileType = ObjectUtils.getNestedValue(businessObject, KRADConstants.BO_ATTACHMENT_FILE_CONTENT_TYPE); field.setImageSrc(WebUtils.getAttachmentImageForUrl((String) fileType)); field.setPropertyValue(fileName); } if (obj != null) { String formattedValue = ObjectUtils.getFormattedPropertyValueUsingDataDictionary(businessObject, field.getPropertyName()); field.setPropertyValue(formattedValue); // for user fields, attempt to pull the principal ID and person's name from the source object if (field.getFieldType().equals(Field.KUALIUSER)) { // this is supplemental, so catch and log any errors try { if (StringUtils.isNotBlank(field.getUniversalIdAttributeName())) { Object principalId = ObjectUtils.getNestedValue(businessObject, field.getUniversalIdAttributeName()); if (principalId != null) { field.setUniversalIdValue(principalId.toString()); } } if (StringUtils.isNotBlank(field.getPersonNameAttributeName())) { Object personName = ObjectUtils.getNestedValue(businessObject, field.getPersonNameAttributeName()); if (personName != null) { field.setPersonNameValue(personName.toString()); } } } catch (Exception ex) { LOG.warn("Unable to get principal ID or person name property in FieldBridge.", ex); } } } populateSecureField(field, obj); } public static void populateSecureField(Field field, Object fieldValue) { // set encrypted & masked value if user does not have permission to see real value in UI // element.isSecure() => a non-null AttributeSecurity object is set in the field if (field.isSecure()) { try { if (fieldValue != null && fieldValue.toString().endsWith(EncryptionService.HASH_POST_PREFIX)) { field.setEncryptedValue(fieldValue.toString()); } else { if (CoreApiServiceLocator.getEncryptionService().isEnabled()) { field.setEncryptedValue(CoreApiServiceLocator.getEncryptionService().encrypt(fieldValue) + EncryptionService.ENCRYPTION_POST_PREFIX); } } } catch (GeneralSecurityException e) { throw new RuntimeException("Unable to encrypt secure field " + e.getMessage()); } //field.setDisplayMaskValue(field.getAttributeSecurity().getDisplayMaskValue(fieldValue)); } } /** * This method indicates whether or not propertyName refers to a nested attribute. * * @param propertyName * @return true if propertyName refers to a nested property (e.g. "x.y") */ static private boolean isPropertyNested(String propertyName) { return -1 != propertyName.indexOf('.'); } /** * This method verifies that all of the parent objects of propertyName are non-null. * * @param bo * @param propertyName * @return true if all parents are non-null, otherwise false */ static private boolean isObjectTreeNonNullAllTheWayDown(BusinessObject bo, String propertyName) { String[] propertyParts = propertyName.split("\\."); StringBuffer property = new StringBuffer(); for (int i = 0; i < propertyParts.length - 1; i++) { property.append((0 == property.length()) ? "" : ".").append(propertyParts[i]); try { if (null == PropertyUtils.getNestedProperty(bo, property.toString())) { return false; } } catch (Throwable t) { LOG.debug("Either getter or setter not specified for property \"" + property.toString() + "\"", t); return false; } } return true; } /** * @param bo * @param propertyName * @return true if one (or more) of the intermediate objects in the given propertyName is null */ private static boolean containsIntermediateNull(Object bo, String propertyName) { boolean containsNull = false; if (StringUtils.contains(propertyName, ".")) { String prefix = StringUtils.substringBefore(propertyName, "."); Object propertyValue = ObjectUtils.getPropertyValue(bo, prefix); if (propertyValue == null) { containsNull = true; } else { String suffix = StringUtils.substringAfter(propertyName, "."); containsNull = containsIntermediateNull(propertyValue, suffix); } } return containsNull; } /** * Uses reflection to get the property names of the business object, then checks for the property name as a key in the passed * map. If found, takes the value from the map and sets the business object property. * * @param bo * @param fieldValues * @return Cached Values from any formatting failures */ public static Map populateBusinessObjectFromMap(BusinessObject bo, Map fieldValues) { return populateBusinessObjectFromMap(bo, fieldValues, ""); } /** * Uses reflection to get the property names of the business object, then checks for the property name as a key in the passed * map. If found, takes the value from the map and sets the business object property. * * @param bo * @param fieldValues * @param propertyNamePrefix this value will be prepended to all property names in the returned unformattable values map * @return Cached Values from any formatting failures */ public static Map populateBusinessObjectFromMap(BusinessObject bo, Map<String, ?> fieldValues, String propertyNamePrefix) { Map cachedValues = new HashMap(); MessageMap errorMap = GlobalVariables.getMessageMap(); try { for (Iterator<String> iter = fieldValues.keySet().iterator(); iter.hasNext();) { String propertyName = iter.next(); if (propertyName.endsWith(KRADConstants.CHECKBOX_PRESENT_ON_FORM_ANNOTATION)) { // since checkboxes do not post values when unchecked, this code detects whether a checkbox was unchecked, and // sets the value to false. if (StringUtils.isNotBlank((String) fieldValues.get(propertyName))) { String checkboxName = StringUtils.removeEnd(propertyName, KRADConstants.CHECKBOX_PRESENT_ON_FORM_ANNOTATION); String checkboxValue = (String) fieldValues.get(checkboxName); if (checkboxValue == null) { // didn't find a checkbox value, assume that it is unchecked if (isPropertyWritable(bo, checkboxName)) { Class type = ObjectUtils.easyGetPropertyType(bo, checkboxName); if (type == Boolean.TYPE || type == Boolean.class) { // ASSUMPTION: unchecked means false ObjectUtils.setObjectProperty(bo, checkboxName, type, "false"); } } } } // else, if not null, then it has a value, and we'll let the rest of the code handle it when the param is processed on // another iteration (may be before or after this iteration). } else if (isPropertyWritable(bo, propertyName) && fieldValues.get(propertyName) != null) { // if the field propertyName is a valid property on the bo class Class type = ObjectUtils.easyGetPropertyType(bo, propertyName); try { Object fieldValue = fieldValues.get(propertyName); ObjectUtils.setObjectProperty(bo, propertyName, type, fieldValue); } catch (FormatException e) { cachedValues.put(propertyNamePrefix + propertyName, fieldValues.get(propertyName)); errorMap.putError(propertyNamePrefix + propertyName, e.getErrorKey(), e.getErrorArgs()); } } } } catch (IllegalAccessException e) { LOG.error("unable to populate business object" + e.getMessage()); throw new RuntimeException(e.getMessage(), e); } catch (InvocationTargetException e) { LOG.error("unable to populate business object" + e.getMessage()); throw new RuntimeException(e.getMessage(), e); } catch (NoSuchMethodException e) { LOG.error("unable to populate business object" + e.getMessage()); throw new RuntimeException(e.getMessage(), e); } return cachedValues; } /** * Does prefixing and read only settings of a Field UI for display in a maintenance document. * * @param field - the Field object to be displayed * @param keyFieldNames - Primary key property names for the business object being maintained. * @param namePrefix - String to prefix Field names with. * @param maintenanceAction - The maintenance action requested. * @param readOnly - Indicates whether all fields should be read only. * @return Field */ public static Field fixFieldForForm(Field field, List keyFieldNames, String namePrefix, String maintenanceAction, boolean readOnly, MaintenanceDocumentRestrictions auths, String documentStatus, String documentInitiatorPrincipalId) { String propertyName = field.getPropertyName(); // We only need to do the following processing if the field is not a sub section header if (field.containsBOData()) { // don't prefix submit fields, must start with dispatch parameter name if (!propertyName.startsWith(KRADConstants.DISPATCH_REQUEST_PARAMETER)) { // if the developer hasn't set a specific prefix use the one supplied if (field.getPropertyPrefix() == null || field.getPropertyPrefix().equals("")) { field.setPropertyName(namePrefix + propertyName); } else { field.setPropertyName(field.getPropertyPrefix() + "." + propertyName); } } if (readOnly) { field.setReadOnly(true); } // set keys read only for edit if (KRADConstants.MAINTENANCE_EDIT_ACTION.equals(maintenanceAction)) { if (keyFieldNames.contains(propertyName)) { field.setReadOnly(true); field.setKeyField(true); } else if (StringUtils.isNotBlank(field.getUniversalIdAttributeName()) && keyFieldNames.contains(field.getUniversalIdAttributeName())) { // special handling for when the principal ID is the PK field for a record // this causes locking down of the user ID field field.setReadOnly(true); field.setKeyField(true); } } // apply any authorization restrictions to field availability on the UI applyAuthorization(field, maintenanceAction, auths, documentStatus, documentInitiatorPrincipalId); // if fieldConversions specified, prefix with new constant if (StringUtils.isNotBlank(field.getFieldConversions())) { String fieldConversions = field.getFieldConversions(); String newFieldConversions = KRADConstants.EMPTY_STRING; String[] conversions = StringUtils.split(fieldConversions, KRADConstants.FIELD_CONVERSIONS_SEPARATOR); for (int l = 0; l < conversions.length; l++) { String conversion = conversions[l]; //String[] conversionPair = StringUtils.split(conversion, KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR); String[] conversionPair = StringUtils.split(conversion, KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR, 2); String conversionFrom = conversionPair[0]; String conversionTo = conversionPair[1]; conversionTo = KRADConstants.MAINTENANCE_NEW_MAINTAINABLE + conversionTo; newFieldConversions += (conversionFrom + KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR + conversionTo); if (l < conversions.length) { newFieldConversions += KRADConstants.FIELD_CONVERSIONS_SEPARATOR; } } field.setFieldConversions(newFieldConversions); } // if inquiryParameters specified, prefix with new constant if (StringUtils.isNotBlank(field.getInquiryParameters())) { String inquiryParameters = field.getInquiryParameters(); StringBuilder newInquiryParameters = new StringBuilder(); String[] parameters = StringUtils.split(inquiryParameters, KRADConstants.FIELD_CONVERSIONS_SEPARATOR); for (int l = 0; l < parameters.length; l++) { String parameter = parameters[l]; //String[] parameterPair = StringUtils.split(parameter, KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR); String[] parameterPair = StringUtils.split(parameter, KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR, 2); String conversionFrom = parameterPair[0]; String conversionTo = parameterPair[1]; // append the conversionFrom string, prefixed by document.newMaintainable newInquiryParameters.append(KRADConstants.MAINTENANCE_NEW_MAINTAINABLE).append(conversionFrom); newInquiryParameters.append(KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR).append(conversionTo); if (l < parameters.length - 1) { newInquiryParameters.append(KRADConstants.FIELD_CONVERSIONS_SEPARATOR); } } field.setInquiryParameters(newInquiryParameters.toString()); } if (Field.KUALIUSER.equals(field.getFieldType())) { // prefix the personNameAttributeName int suffixIndex = field.getPropertyName().indexOf(field.getUserIdAttributeName()); if (suffixIndex != -1) { field.setPersonNameAttributeName( field.getPropertyName().substring(0, suffixIndex) + field.getPersonNameAttributeName()); field.setUniversalIdAttributeName(field.getPropertyName().substring(0, suffixIndex) + field.getUniversalIdAttributeName()); } else { field.setPersonNameAttributeName(namePrefix + field.getPersonNameAttributeName()); field.setUniversalIdAttributeName(namePrefix + field.getUniversalIdAttributeName()); } // TODO: do we need to prefix the universalIdAttributeName in Field as well? } // if lookupParameters specified, prefix with new constant if (StringUtils.isNotBlank(field.getLookupParameters())) { String lookupParameters = field.getLookupParameters(); String newLookupParameters = KRADConstants.EMPTY_STRING; String[] conversions = StringUtils.split(lookupParameters, KRADConstants.FIELD_CONVERSIONS_SEPARATOR); for (int m = 0; m < conversions.length; m++) { String conversion = conversions[m]; //String[] conversionPair = StringUtils.split(conversion, KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR); String[] conversionPair = StringUtils.split(conversion, KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR, 2); String conversionFrom = conversionPair[0]; String conversionTo = conversionPair[1]; conversionFrom = KRADConstants.MAINTENANCE_NEW_MAINTAINABLE + conversionFrom; newLookupParameters += (conversionFrom + KRADConstants.FIELD_CONVERSION_PAIR_SEPARATOR + conversionTo); if (m < conversions.length) { newLookupParameters += KRADConstants.FIELD_CONVERSIONS_SEPARATOR; } } field.setLookupParameters(newLookupParameters); } // CONTAINER field types have nested rows and fields that need setup for the form if (Field.CONTAINER.equals(field.getFieldType())) { List containerRows = field.getContainerRows(); List fixedRows = new ArrayList(); for (Iterator iter = containerRows.iterator(); iter.hasNext();) { Row containerRow = (Row) iter.next(); List containerFields = containerRow.getFields(); List fixedFields = new ArrayList(); for (Iterator iterator = containerFields.iterator(); iterator.hasNext();) { Field containerField = (Field) iterator.next(); containerField = fixFieldForForm(containerField, keyFieldNames, namePrefix, maintenanceAction, readOnly, auths, documentStatus, documentInitiatorPrincipalId); fixedFields.add(containerField); } fixedRows.add(new Row(fixedFields)); } field.setContainerRows(fixedRows); } } return field; } public static void applyAuthorization(Field field, String maintenanceAction, MaintenanceDocumentRestrictions auths, String documentStatus, String documentInitiatorPrincipalId) { String fieldName = ""; FieldRestriction fieldAuth = null; Person user = GlobalVariables.getUserSession().getPerson(); // only apply this on the newMaintainable if (field.getPropertyName().startsWith(KRADConstants.MAINTENANCE_NEW_MAINTAINABLE)) { // get just the actual fieldName, with the document.newMaintainableObject, etc etc removed fieldName = field.getPropertyName().substring(KRADConstants.MAINTENANCE_NEW_MAINTAINABLE.length()); // if the field is restricted somehow if (auths.hasRestriction(fieldName)) { fieldAuth = auths.getFieldRestriction(fieldName); if (KRADConstants.MAINTENANCE_NEW_ACTION.equals(maintenanceAction) || KRADConstants.MAINTENANCE_COPY_ACTION.equals(maintenanceAction)) { if ((KewApiConstants.ROUTE_HEADER_SAVED_CD.equals(documentStatus) || KewApiConstants.ROUTE_HEADER_INITIATED_CD.equals(documentStatus)) && user.getPrincipalId().equals(documentInitiatorPrincipalId)) { //user should be able to see the unmark value } else { if (fieldAuth.isPartiallyMasked()) { field.setSecure(true); fieldAuth.setShouldBeEncrypted(true); MaskFormatter maskFormatter = fieldAuth.getMaskFormatter(); String displayMaskValue = maskFormatter.maskValue(field.getPropertyValue()); field.setDisplayMaskValue(displayMaskValue); populateSecureField(field, field.getPropertyValue()); } else if (fieldAuth.isMasked()) { field.setSecure(true); fieldAuth.setShouldBeEncrypted(true); MaskFormatter maskFormatter = fieldAuth.getMaskFormatter(); String displayMaskValue = maskFormatter.maskValue(field.getPropertyValue()); field.setDisplayMaskValue(displayMaskValue); populateSecureField(field, field.getPropertyValue()); } } } if (KRADConstants.MAINTENANCE_EDIT_ACTION.equals(maintenanceAction) || KRADConstants.MAINTENANCE_NEWWITHEXISTING_ACTION.equals(maintenanceAction)) { // if there's existing data on the page that we're not going to clear out, then we will mask it out if (fieldAuth.isPartiallyMasked()) { field.setSecure(true); fieldAuth.setShouldBeEncrypted(true); MaskFormatter maskFormatter = fieldAuth.getMaskFormatter(); String displayMaskValue = maskFormatter.maskValue(field.getPropertyValue()); field.setDisplayMaskValue(displayMaskValue); populateSecureField(field, field.getPropertyValue()); } else if (fieldAuth.isMasked()) { field.setSecure(true); fieldAuth.setShouldBeEncrypted(true); MaskFormatter maskFormatter = fieldAuth.getMaskFormatter(); String displayMaskValue = maskFormatter.maskValue(field.getPropertyValue()); field.setDisplayMaskValue(displayMaskValue); populateSecureField(field, field.getPropertyValue()); } } if (Field.isInputField(field.getFieldType()) || field.getFieldType().equalsIgnoreCase(Field.CHECKBOX)) { // if its an editable field, allow decreasing availability to readonly or hidden // only touch the field if the restricted type is hidden or readonly if (fieldAuth.isReadOnly()) { if (!field.isReadOnly() && !fieldAuth.isMasked() && !fieldAuth.isPartiallyMasked()) { field.setReadOnly(true); } } else if (fieldAuth.isHidden()) { if (field.getFieldType() != Field.HIDDEN) { field.setFieldType(Field.HIDDEN); } } } if (Field.BUTTON.equalsIgnoreCase(field.getFieldType()) && fieldAuth.isHidden()) { field.setFieldType(Field.HIDDEN); } // if the field is readOnly, and the authorization says it should be hidden, // then restrict it if (field.isReadOnly() && fieldAuth.isHidden()) { field.setFieldType(Field.HIDDEN); } } // special check for old maintainable - need to ensure that fields hidden on the // "new" side are also hidden on the old side } else if (field.getPropertyName().startsWith(KRADConstants.MAINTENANCE_OLD_MAINTAINABLE)) { // get just the actual fieldName, with the document.oldMaintainableObject, etc etc removed fieldName = field.getPropertyName().substring(KRADConstants.MAINTENANCE_OLD_MAINTAINABLE.length()); // if the field is restricted somehow if (auths.hasRestriction(fieldName)) { fieldAuth = auths.getFieldRestriction(fieldName); if (fieldAuth.isPartiallyMasked()) { field.setSecure(true); MaskFormatter maskFormatter = fieldAuth.getMaskFormatter(); String displayMaskValue = maskFormatter.maskValue(field.getPropertyValue()); field.setDisplayMaskValue(displayMaskValue); field.setPropertyValue(displayMaskValue); populateSecureField(field, field.getPropertyValue()); } if (fieldAuth.isMasked()) { field.setSecure(true); MaskFormatter maskFormatter = fieldAuth.getMaskFormatter(); String displayMaskValue = maskFormatter.maskValue(field.getPropertyValue()); field.setDisplayMaskValue(displayMaskValue); field.setPropertyValue(displayMaskValue); populateSecureField(field, field.getPropertyValue()); } if (fieldAuth.isHidden()) { field.setFieldType(Field.HIDDEN); } } } } /** * Merges together sections of the old maintainable and new maintainable. * * @param oldSections * @param newSections * @param keyFieldNames * @param maintenanceAction * @param readOnly * @return List of Section objects */ public static List meshSections(List oldSections, List newSections, List keyFieldNames, String maintenanceAction, boolean readOnly, MaintenanceDocumentRestrictions auths, String documentStatus, String documentInitiatorPrincipalId) { List meshedSections = new ArrayList(); for (int i = 0; i < newSections.size(); i++) { Section maintSection = (Section) newSections.get(i); List sectionRows = maintSection.getRows(); Section oldMaintSection = (Section) oldSections.get(i); List oldSectionRows = oldMaintSection.getRows(); List<Row> meshedRows = new ArrayList(); meshedRows = meshRows(oldSectionRows, sectionRows, keyFieldNames, maintenanceAction, readOnly, auths, documentStatus, documentInitiatorPrincipalId); maintSection.setRows(meshedRows); if (StringUtils.isBlank(maintSection.getErrorKey())) { maintSection.setErrorKey(MaintenanceUtils.generateErrorKeyForSection(maintSection)); } meshedSections.add(maintSection); } return meshedSections; } /** * Merges together rows of an old maintainable section and new maintainable section. * * @param oldRows * @param newRows * @param keyFieldNames * @param maintenanceAction * @param readOnly * @return List of Row objects */ public static List meshRows(List oldRows, List newRows, List keyFieldNames, String maintenanceAction, boolean readOnly, MaintenanceDocumentRestrictions auths, String documentStatus, String documentInitiatorPrincipalId) { List<Row> meshedRows = new ArrayList<Row>(); for (int j = 0; j < newRows.size(); j++) { Row sectionRow = (Row) newRows.get(j); List rowFields = sectionRow.getFields(); Row oldSectionRow = null; List oldRowFields = new ArrayList(); if (null != oldRows && oldRows.size() > j) { oldSectionRow = (Row) oldRows.get(j); oldRowFields = oldSectionRow.getFields(); } List meshedFields = meshFields(oldRowFields, rowFields, keyFieldNames, maintenanceAction, readOnly, auths, documentStatus, documentInitiatorPrincipalId); if (meshedFields.size() > 0) { Row meshedRow = new Row(meshedFields); if (sectionRow.isHidden()) { meshedRow.setHidden(true); } meshedRows.add(meshedRow); } } return meshedRows; } /** * Merges together fields and an old maintainble row and new maintainable row, for each field call fixFieldForForm. * * @param oldFields * @param newFields * @param keyFieldNames * @param maintenanceAction * @param readOnly * @return List of Field objects */ public static List meshFields(List oldFields, List newFields, List keyFieldNames, String maintenanceAction, boolean readOnly, MaintenanceDocumentRestrictions auths, String documentStatus, String documentInitiatorPrincipalId) { List meshedFields = new ArrayList(); List newFieldsToMerge = new ArrayList(); List oldFieldsToMerge = new ArrayList(); for (int k = 0; k < newFields.size(); k++) { Field newMaintField = (Field) newFields.get(k); String propertyName = newMaintField.getPropertyName(); // If this is an add button, then we have to have only this field for the entire row. if (Field.IMAGE_SUBMIT.equals(newMaintField.getFieldType())) { meshedFields.add(newMaintField); } else if (Field.CONTAINER.equals(newMaintField.getFieldType())) { if (oldFields.size() > k) { Field oldMaintField = (Field) oldFields.get(k); newMaintField = meshContainerFields(oldMaintField, newMaintField, keyFieldNames, maintenanceAction, readOnly, auths, documentStatus, documentInitiatorPrincipalId); } else { newMaintField = meshContainerFields(newMaintField, newMaintField, keyFieldNames, maintenanceAction, readOnly, auths, documentStatus, documentInitiatorPrincipalId); } meshedFields.add(newMaintField); } else { newMaintField = FieldUtils.fixFieldForForm(newMaintField, keyFieldNames, KRADConstants.MAINTENANCE_NEW_MAINTAINABLE, maintenanceAction, readOnly, auths, documentStatus, documentInitiatorPrincipalId); // add old fields for edit if (KRADConstants.MAINTENANCE_EDIT_ACTION.equals(maintenanceAction) || KRADConstants.MAINTENANCE_COPY_ACTION.equals(maintenanceAction)) { Field oldMaintField = (Field) oldFields.get(k); // compare values for change, and set new maintainable fields for highlighting // no point in highlighting the hidden fields, since they won't be rendered anyways if (!StringUtils.equalsIgnoreCase(newMaintField.getPropertyValue(), oldMaintField.getPropertyValue()) && !Field.HIDDEN.equals(newMaintField.getFieldType())) { newMaintField.setHighlightField(true); } oldMaintField = FieldUtils.fixFieldForForm(oldMaintField, keyFieldNames, KRADConstants.MAINTENANCE_OLD_MAINTAINABLE, maintenanceAction, true, auths, documentStatus, documentInitiatorPrincipalId); oldFieldsToMerge.add(oldMaintField); } newFieldsToMerge.add(newMaintField); for (Iterator iter = oldFieldsToMerge.iterator(); iter.hasNext();) { Field element = (Field) iter.next(); meshedFields.add(element); } for (Iterator iter = newFieldsToMerge.iterator(); iter.hasNext();) { Field element = (Field) iter.next(); meshedFields.add(element); } } } return meshedFields; } /** * Determines whether field level help is enabled for the field corresponding to the dataObjectClass and attribute name * * If this value is true, then the field level help will be enabled. * If false, then whether a field is enabled is determined by the value returned by {@link #isLookupFieldLevelHelpDisabled(Class, String)} and the system-wide * parameter setting. Note that if a field is read-only, that may cause field-level help to not be rendered. * * @param businessObjectClass the looked up class * @param attributeName the attribute for the field * @return true if field level help is enabled, false if the value of this method should NOT be used to determine whether this method's return value * affects the enablement of field level help */ protected static boolean isLookupFieldLevelHelpEnabled(Class businessObjectClass, String attributeName) { return false; } /** * Determines whether field level help is disabled for the field corresponding to the dataObjectClass and attribute name * * If this value is true and {@link #isLookupFieldLevelHelpEnabled(Class, String)} returns false, * then the field level help will not be rendered. If both this and {@link #isLookupFieldLevelHelpEnabled(Class, String)} return false, then the system-wide * setting will determine whether field level help is enabled. Note that if a field is read-only, that may cause field-level help to not be rendered. * * @param businessObjectClass the looked up class * @param attributeName the attribute for the field * @return true if field level help is disabled, false if the value of this method should NOT be used to determine whether this method's return value * affects the enablement of field level help */ protected static boolean isLookupFieldLevelHelpDisabled(Class businessObjectClass, String attributeName) { return false; } public static List<Field> createAndPopulateFieldsForLookup(List<String> lookupFieldAttributeList, List<String> readOnlyFieldsList, Class businessObjectClass) throws InstantiationException, IllegalAccessException { List<Field> fields = new ArrayList<Field>(); BusinessObjectEntry boe = (BusinessObjectEntry) getDataDictionaryService().getDataDictionary() .getBusinessObjectEntry(businessObjectClass.getName()); Map<String, Boolean> isHiddenMap = new HashMap<String, Boolean>(); Map<String, Boolean> isReadOnlyMap = new HashMap<String, Boolean>(); /* * Check if any field is hidden or read only. This allows us to * set lookup criteria as hidden/readonly outside the controlDefinition. */ if (boe.hasLookupDefinition()) { List<FieldDefinition> fieldDefs = boe.getLookupDefinition().getLookupFields(); for (FieldDefinition field : fieldDefs) { isReadOnlyMap.put(field.getAttributeName(), Boolean.valueOf(field.isReadOnly())); isHiddenMap.put(field.getAttributeName(), Boolean.valueOf(field.isHidden())); } } for (String attributeName : lookupFieldAttributeList) { Field field = FieldUtils.getPropertyField(businessObjectClass, attributeName, true); if (field.isDatePicker() && field.isRanged()) { Field newDate = createRangeDateField(field); fields.add(newDate); } BusinessObject newBusinessObjectInstance; if (ExternalizableBusinessObjectUtils.isExternalizableBusinessObjectInterface(businessObjectClass)) { ModuleService moduleService = getKualiModuleService() .getResponsibleModuleService(businessObjectClass); newBusinessObjectInstance = (BusinessObject) moduleService .createNewObjectFromExternalizableClass(businessObjectClass); } else { newBusinessObjectInstance = (BusinessObject) businessObjectClass.newInstance(); } //quickFinder is synonymous with a field-based Lookup field = LookupUtils.setFieldQuickfinder(newBusinessObjectInstance, attributeName, field, lookupFieldAttributeList); field = LookupUtils.setFieldDirectInquiry(newBusinessObjectInstance, attributeName, field); // overwrite maxLength to allow for wildcards and ranges in the select, but only if it's not a mulitselect box, because maxLength determines the # of entries if (!Field.MULTISELECT.equals(field.getFieldType())) { field.setMaxLength(100); } // if the attrib name is "active", and BO is Inactivatable, then set the default value to Y if (attributeName.equals(KRADPropertyConstants.ACTIVE) && MutableInactivatable.class.isAssignableFrom(businessObjectClass)) { field.setPropertyValue(KRADConstants.YES_INDICATOR_VALUE); field.setDefaultValue(KRADConstants.YES_INDICATOR_VALUE); } // set default value String defaultValue = getBusinessObjectMetaDataService().getLookupFieldDefaultValue(businessObjectClass, attributeName); if (defaultValue != null) { field.setPropertyValue(defaultValue); field.setDefaultValue(defaultValue); } Class defaultValueFinderClass = getBusinessObjectMetaDataService() .getLookupFieldDefaultValueFinderClass(businessObjectClass, attributeName); //getBusinessObjectMetaDataService().getLookupFieldDefaultValue(dataObjectClass, attributeName) if (defaultValueFinderClass != null) { field.setPropertyValue(((ValueFinder) defaultValueFinderClass.newInstance()).getValue()); field.setDefaultValue(((ValueFinder) defaultValueFinderClass.newInstance()).getValue()); } if ((readOnlyFieldsList != null && readOnlyFieldsList.contains(field.getPropertyName())) || (isReadOnlyMap.containsKey(field.getPropertyName()) && isReadOnlyMap.get(field.getPropertyName()).booleanValue())) { field.setReadOnly(true); } populateQuickfinderDefaultsForLookup(businessObjectClass, attributeName, field); if ((isHiddenMap.containsKey(field.getPropertyName()) && isHiddenMap.get(field.getPropertyName()).booleanValue())) { field.setFieldType(Field.HIDDEN); } boolean triggerOnChange = getBusinessObjectDictionaryService() .isLookupFieldTriggerOnChange(businessObjectClass, attributeName); field.setTriggerOnChange(triggerOnChange); field.setFieldLevelHelpEnabled(isLookupFieldLevelHelpEnabled(businessObjectClass, attributeName)); field.setFieldLevelHelpDisabled(isLookupFieldLevelHelpDisabled(businessObjectClass, attributeName)); fields.add(field); } return fields; } /** * This method ... * * @param businessObjectClass * @param attributeName * @param field * @throws InstantiationException * @throws IllegalAccessException */ private static void populateQuickfinderDefaultsForLookup(Class businessObjectClass, String attributeName, Field field) throws InstantiationException, IllegalAccessException { // handle quickfinderParameterString / quickfinderParameterFinderClass String quickfinderParamString = getBusinessObjectMetaDataService() .getLookupFieldQuickfinderParameterString(businessObjectClass, attributeName); Class<? extends ValueFinder> quickfinderParameterFinderClass = getBusinessObjectMetaDataService() .getLookupFieldQuickfinderParameterStringBuilderClass(businessObjectClass, attributeName); if (quickfinderParameterFinderClass != null) { quickfinderParamString = quickfinderParameterFinderClass.newInstance().getValue(); } if (!StringUtils.isEmpty(quickfinderParamString)) { String[] params = quickfinderParamString.split(","); if (params != null) for (String param : params) { if (param.contains(KRADConstants.LOOKUP_PARAMETER_LITERAL_DELIMITER)) { String[] paramChunks = param.split(KRADConstants.LOOKUP_PARAMETER_LITERAL_DELIMITER, 2); field.appendLookupParameters(KRADConstants.LOOKUP_PARAMETER_LITERAL_PREFIX + KRADConstants.LOOKUP_PARAMETER_LITERAL_DELIMITER + paramChunks[1] + ":" + paramChunks[0]); } } } } /** * creates an extra field for date from/to ranges * @param field * @return a new date field */ public static Field createRangeDateField(Field field) { Field newDate = (Field) SerializationUtils.deepCopy(field); newDate.setFieldLabel( newDate.getFieldLabel() + " " + KRADConstants.LOOKUP_DEFAULT_RANGE_SEARCH_LOWER_BOUND_LABEL); field.setFieldLabel( field.getFieldLabel() + " " + KRADConstants.LOOKUP_DEFAULT_RANGE_SEARCH_UPPER_BOUND_LABEL); newDate.setPropertyName(KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX + newDate.getPropertyName()); return newDate; } private static Field meshContainerFields(Field oldMaintField, Field newMaintField, List keyFieldNames, String maintenanceAction, boolean readOnly, MaintenanceDocumentRestrictions auths, String documentStatus, String documentInitiatorPrincipalId) { List resultingRows = new ArrayList(); resultingRows.addAll(meshRows(oldMaintField.getContainerRows(), newMaintField.getContainerRows(), keyFieldNames, maintenanceAction, readOnly, auths, documentStatus, documentInitiatorPrincipalId)); Field resultingField = newMaintField; resultingField.setFieldType(Field.CONTAINER); // save the summary info resultingField.setContainerElementName(newMaintField.getContainerElementName()); resultingField.setContainerDisplayFields(newMaintField.getContainerDisplayFields()); resultingField.setNumberOfColumnsForCollection(newMaintField.getNumberOfColumnsForCollection()); resultingField.setContainerRows(resultingRows); List resultingRowsList = newMaintField.getContainerRows(); if (resultingRowsList.size() > 0) { List resultingFieldsList = ((Row) resultingRowsList.get(0)).getFields(); if (resultingFieldsList.size() > 0) { // todo: assign the correct propertyName to the container in the first place. For now, I'm wary of the weird usages // of constructContainerField(). String containedFieldName = ((Field) (resultingFieldsList.get(0))).getPropertyName(); resultingField .setPropertyName(containedFieldName.substring(0, containedFieldName.lastIndexOf('.'))); } } else { resultingField.setPropertyName(oldMaintField.getPropertyName()); } return resultingField; } /** * This method modifies the passed in field so that it may be used to render a multiple values lookup button * * @param field this object will be modified by this method * @param parents * @param definition */ static final public void modifyFieldToSupportMultipleValueLookups(Field field, String parents, MaintainableCollectionDefinition definition) { field.setMultipleValueLookedUpCollectionName(parents + definition.getName()); field.setMultipleValueLookupClassName(definition.getSourceClassName().getName()); field.setMultipleValueLookupClassLabel(getDataDictionaryService().getDataDictionary() .getBusinessObjectEntry(definition.getSourceClassName().getName()).getObjectLabel()); } /** * Returns whether the passed in collection has been properly configured in the maint doc dictionary to support multiple value * lookups. * * @param definition * @return */ static final public boolean isCollectionMultipleLookupEnabled(MaintainableCollectionDefinition definition) { return definition.getSourceClassName() != null && definition.isIncludeMultipleLookupLine(); } /** * This method removes any duplicating spacing (internal or on the ends) from a String, meant to be exposed as a tag library * function. * * @param s String to remove duplicate spacing from. * @return String without duplicate spacing. */ public static String scrubWhitespace(String s) { return s.replaceAll("(\\s)(\\s+)", " "); } public static List<Row> convertRemotableAttributeFields( List<RemotableAttributeField> remotableAttributeFields) { List<Row> rows = new ArrayList<Row>(); for (RemotableAttributeField remotableAttributeField : remotableAttributeFields) { List<Field> fields = convertRemotableAttributeField(remotableAttributeField); // each field goes in it's own row... for (Field field : fields) { Row row = new Row(field); rows.add(row); } } return rows; } public static List<Field> convertRemotableAttributeField(RemotableAttributeField remotableAttributeField) { // will produce two fields in the case of a range List<Field> fields = constructFieldsForAttributeDefinition(remotableAttributeField); for (Field field : fields) { applyControlAttributes(remotableAttributeField, field); applyLookupAttributes(remotableAttributeField, field); applyWidgetAttributes(remotableAttributeField, field); } return fields; } private static List<Field> constructFieldsForAttributeDefinition( RemotableAttributeField remotableAttributeField) { List<Field> fields = new ArrayList<Field>(); if (remotableAttributeField.getAttributeLookupSettings() != null && remotableAttributeField.getAttributeLookupSettings().isRanged()) { // create two fields, one for the "from" and one for the "to" AttributeLookupSettings lookupSettings = remotableAttributeField.getAttributeLookupSettings(); // Create a pair of range input fields for a ranged attribute // the lower bound is prefixed to distinguish it from the upper bound, which retains the original field name String attrLabel; if (StringUtils.isBlank(remotableAttributeField.getLongLabel())) { attrLabel = remotableAttributeField.getShortLabel(); } else { attrLabel = remotableAttributeField.getLongLabel(); } String label = StringUtils.defaultString(lookupSettings.getLowerLabel(), attrLabel + " " + KewApiConstants.SearchableAttributeConstants.DEFAULT_RANGE_SEARCH_LOWER_BOUND_LABEL); Field lowerField = new Field( KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX + remotableAttributeField.getName(), label); lowerField.setMemberOfRange(true); lowerField.setAllowInlineRange(false); lowerField.setRangeFieldInclusive(lookupSettings.isLowerBoundInclusive()); if (lookupSettings.isLowerDatePicker() != null) { lowerField.setDatePicker(lookupSettings.isLowerDatePicker()); } if (!remotableAttributeField.getDataType().equals(DataType.CURRENCY)) { lowerField.setFieldDataType(remotableAttributeField.getDataType().name().toLowerCase()); } fields.add(lowerField); label = StringUtils.defaultString(lookupSettings.getUpperLabel(), attrLabel + " " + KewApiConstants.SearchableAttributeConstants.DEFAULT_RANGE_SEARCH_UPPER_BOUND_LABEL); Field upperField = new Field(remotableAttributeField.getName(), label); upperField.setMemberOfRange(true); upperField.setAllowInlineRange(false); upperField.setRangeFieldInclusive(lookupSettings.isUpperBoundInclusive()); if (lookupSettings.isUpperDatePicker() != null) { upperField.setDatePicker(lookupSettings.isUpperDatePicker()); } if (!remotableAttributeField.getDataType().equals(DataType.CURRENCY)) { upperField.setFieldDataType(remotableAttributeField.getDataType().name().toLowerCase()); } fields.add(upperField); } else { //this ain't right.... Field tempField = new Field(remotableAttributeField.getName(), remotableAttributeField.getLongLabel()); if (remotableAttributeField.getMaxLength() != null) { tempField.setMaxLength(remotableAttributeField.getMaxLength()); } if (remotableAttributeField.getShortLabel() != null) { tempField.setFieldLabel(remotableAttributeField.getShortLabel()); } if (!remotableAttributeField.getDataType().equals(DataType.CURRENCY)) { tempField.setFieldDataType(remotableAttributeField.getDataType().name().toLowerCase()); } else { tempField.setFieldDataType(KewApiConstants.SearchableAttributeConstants.DATA_TYPE_FLOAT); } tempField.setMainFieldLabel(remotableAttributeField.getLongLabel()); tempField.setFieldHelpSummary(remotableAttributeField.getHelpSummary()); tempField.setUpperCase(remotableAttributeField.isForceUpperCase()); if (remotableAttributeField.getMaxLength() != null) { if (remotableAttributeField.getMaxLength().intValue() > 0) { tempField.setMaxLength(remotableAttributeField.getMaxLength().intValue()); } else { tempField.setMaxLength(100); } } tempField.setFieldRequired(remotableAttributeField.isRequired()); fields.add(tempField); } return fields; } public static List<RemotableAttributeField> convertRowsToAttributeFields(List<Row> rows) { List<RemotableAttributeField> attributeFields = new ArrayList<RemotableAttributeField>(); for (Row row : rows) { attributeFields.addAll(convertRowToAttributeFields(row)); } return attributeFields; } public static List<RemotableAttributeField> convertRowToAttributeFields(Row row) { List<RemotableAttributeField> attributeFields = new ArrayList<RemotableAttributeField>(); for (Field field : row.getFields()) { RemotableAttributeField remotableAttributeField = convertFieldToAttributeField(field); if (remotableAttributeField != null) { attributeFields.add(remotableAttributeField); } } return attributeFields; } public static RemotableAttributeField convertFieldToAttributeField(Field field) { RemotableAttributeField.Builder builder = RemotableAttributeField.Builder.create(field.getPropertyName()); List<RemotableAbstractWidget.Builder> widgets = new ArrayList<RemotableAbstractWidget.Builder>(); builder.setDataType(DataType.valueOf(field.getFieldDataType().toUpperCase())); builder.setShortLabel(field.getFieldLabel()); builder.setLongLabel(field.getMainFieldLabel()); builder.setHelpSummary(field.getFieldHelpSummary()); //builder.setConstraintText(field.) //builder.setHelpDescription(); builder.setForceUpperCase(field.isUpperCase()); //builder.setMinLength() if (field.getMaxLength() > 0) { builder.setMaxLength(new Integer(field.getMaxLength())); } else { builder.setMaxLength(new Integer(100)); } //builder.setMinValue(); //builder.setMaxValue(); //builder.setRegexConstraint(field.); //builder.setRegexContraintMsg(); builder.setRequired(field.isFieldRequired()); builder.setDefaultValues(Collections.singletonList(field.getDefaultValue())); builder.setControl(FieldUtils.constructControl(field, field.getFieldValidValues())); if (field.getHasLookupable()) { builder.setAttributeLookupSettings(RemotableAttributeLookupSettings.Builder.create()); RemotableQuickFinder.Builder quickfinder = RemotableQuickFinder.Builder.create(field.getBaseLookupUrl(), field.getQuickFinderClassNameImpl()); quickfinder.setFieldConversions(toMap(field.getFieldConversions())); quickfinder.setLookupParameters(toMap(field.getLookupParameters())); widgets.add(quickfinder); } RemotableAttributeLookupSettings.Builder lookupSettings = null; if (builder.getDataType().equals(DataType.DATETIME) || builder.getDataType().equals(DataType.DATE)) { if (field.isRanged()) { lookupSettings = RemotableAttributeLookupSettings.Builder.create(); lookupSettings.setRanged(field.isRanged()); if (field.isDatePicker()) { lookupSettings.setLowerDatePicker(Boolean.TRUE); lookupSettings.setUpperDatePicker(Boolean.TRUE); } if (ObjectUtils.isNull(field.getRangeFieldInclusive())) { lookupSettings.setUpperBoundInclusive(true); lookupSettings.setLowerBoundInclusive(true); } } } if (!field.isColumnVisible()) { if (ObjectUtils.isNull(lookupSettings)) { lookupSettings = RemotableAttributeLookupSettings.Builder.create(); } lookupSettings.setInResults(field.isColumnVisible()); } if (ObjectUtils.isNotNull(lookupSettings)) { builder.setAttributeLookupSettings(lookupSettings); } if (field.getFieldType().equals(Field.CURRENCY)) { builder.setDataType(DataType.CURRENCY); builder.setMaxLength(field.getFormattedMaxLength()); } if (field.isDatePicker()) { widgets.add(RemotableDatepicker.Builder.create()); } if (field.isExpandedTextArea()) { widgets.add(RemotableTextExpand.Builder.create()); } builder.setWidgets(widgets); return builder.build(); } private static RemotableAbstractControl.Builder constructControl(Field field, List<KeyValue> options) { //RemotableAbstractControl.Builder control = null; Map<String, String> optionMap = new LinkedHashMap<String, String>(); if (options != null) { for (KeyValue option : options) { optionMap.put(option.getKey(), option.getValue()); } } String type = field.getFieldType(); if (Field.TEXT.equals(type) || Field.DATEPICKER.equals(type)) { RemotableTextInput.Builder control = RemotableTextInput.Builder.create(); control.setSize(field.getSize()); return control; } else if (Field.TEXT_AREA.equals(type)) { RemotableTextarea.Builder control = RemotableTextarea.Builder.create(); control.setCols(field.getCols()); control.setRows(field.getRows()); return control; } else if (Field.DROPDOWN.equals(type)) { return RemotableSelect.Builder.create(optionMap); } else if (Field.DROPDOWN_REFRESH.equals(type)) { RemotableSelect.Builder control = RemotableSelect.Builder.create(optionMap); control.setRefreshOnChange(true); return control; } else if (Field.CHECKBOX.equals(type)) { return RemotableCheckbox.Builder.create(); } else if (Field.RADIO.equals(type)) { return RemotableRadioButtonGroup.Builder.create(optionMap); } else if (Field.HIDDEN.equals(type)) { return RemotableHiddenInput.Builder.create(); } else if (Field.MULTIBOX.equals(type)) { RemotableSelect.Builder control = RemotableSelect.Builder.create(optionMap); control.setMultiple(true); return control; } else if (Field.MULTISELECT.equals(type)) { RemotableSelect.Builder control = RemotableSelect.Builder.create(optionMap); control.setMultiple(true); return control; } else if (Field.CURRENCY.equals(type)) { RemotableTextInput.Builder control = RemotableTextInput.Builder.create(); control.setSize(field.getSize()); return control; } else { throw new IllegalArgumentException("Illegal field type found: " + type); } } private static void applyControlAttributes(RemotableAttributeField remotableField, Field field) { RemotableControlContract control = remotableField.getControl(); String fieldType = null; if (control == null) { throw new IllegalStateException("Given attribute field with the following name has a null control: " + remotableField.getName()); } if (control == null || control instanceof RemotableTextInput) { fieldType = Field.TEXT; if (((RemotableTextInput) remotableField.getControl()).getSize() != null) { field.setSize(((RemotableTextInput) remotableField.getControl()).getSize().intValue()); } if (((RemotableTextInput) remotableField.getControl()).getSize() != null) { field.setFormattedMaxLength( ((RemotableTextInput) remotableField.getControl()).getSize().intValue()); } } else if (control instanceof RemotableCheckboxGroup) { RemotableCheckboxGroup checkbox = (RemotableCheckboxGroup) control; fieldType = Field.CHECKBOX; field.setFieldValidValues(FieldUtils.convertMapToKeyValueList(checkbox.getKeyLabels())); } else if (control instanceof RemotableCheckbox) { fieldType = Field.CHECKBOX; } else if (control instanceof RemotableHiddenInput) { fieldType = Field.HIDDEN; } else if (control instanceof RemotablePasswordInput) { throw new IllegalStateException("Password control not currently supported."); } else if (control instanceof RemotableRadioButtonGroup) { fieldType = Field.RADIO; RemotableRadioButtonGroup radioControl = (RemotableRadioButtonGroup) control; field.setFieldValidValues(FieldUtils.convertMapToKeyValueList(radioControl.getKeyLabels())); } else if (control instanceof RemotableSelect) { RemotableSelect selectControl = (RemotableSelect) control; field.setFieldValidValues(FieldUtils.convertMapToKeyValueList(selectControl.getKeyLabels())); if (selectControl.isMultiple()) { fieldType = Field.MULTISELECT; } else if (selectControl.isRefreshOnChange()) { fieldType = Field.DROPDOWN_REFRESH; } else { fieldType = Field.DROPDOWN; } } else if (control instanceof RemotableTextarea) { fieldType = Field.TEXT_AREA; if (((RemotableTextarea) remotableField.getControl()).getCols() != null && ((RemotableTextarea) remotableField.getControl()).getRows() != null) { field.setCols(((RemotableTextarea) remotableField.getControl()).getCols().intValue()); field.setSize(((RemotableTextarea) remotableField.getControl()).getRows().intValue()); } } else { throw new IllegalArgumentException("Given control type is not supported: " + control.getClass()); } // compare setting of Field default values to {@link ComponentFactory#translateRemotableField} if (!remotableField.getDefaultValues().isEmpty()) { field.setDefaultValue(remotableField.getDefaultValues().iterator().next()); // why are these two not related? :/ field.setPropertyValues(remotableField.getDefaultValues() .toArray(new String[remotableField.getDefaultValues().size()])); field.setPropertyValue(field.getDefaultValue()); } field.setFieldType(fieldType); } private static List<KeyValue> convertMapToKeyValueList(Map<String, String> values) { ArrayList<KeyValue> validValues = new ArrayList<KeyValue>(values.size()); for (Map.Entry<String, String> entry : values.entrySet()) { validValues.add(new ConcreteKeyValue(entry.getKey(), entry.getValue())); } return validValues; } private static void applyLookupAttributes(RemotableAttributeField remotableField, Field field) { AttributeLookupSettings lookupSettings = remotableField.getAttributeLookupSettings(); if (lookupSettings != null) { field.setColumnVisible(lookupSettings.isInResults()); if (!lookupSettings.isInCriteria()) { field.setFieldType(Field.HIDDEN); } field.setRanged(lookupSettings.isRanged()); boolean datePickerLow = lookupSettings.isLowerDatePicker() == null ? false : lookupSettings.isLowerDatePicker().booleanValue(); boolean datePickerUpper = lookupSettings.isUpperDatePicker() == null ? false : lookupSettings.isUpperDatePicker().booleanValue(); field.setDatePicker(datePickerLow || datePickerUpper); } } private static void applyWidgetAttributes(RemotableAttributeField remotableField, Field field) { Collection<? extends RemotableAbstractWidget> widgets = remotableField.getWidgets(); for (RemotableAbstractWidget widget : widgets) { //yuck, do we really have to do this if else if stuff here? if (widget instanceof RemotableQuickFinder) { field.setQuickFinderClassNameImpl(((RemotableQuickFinder) widget).getDataObjectClass()); field.setBaseLookupUrl(((RemotableQuickFinder) widget).getBaseLookupUrl()); field.setLookupParameters(((RemotableQuickFinder) widget).getLookupParameters()); field.setFieldConversions(((RemotableQuickFinder) widget).getFieldConversions()); // datepickerness is dealt with in constructFieldsForAttributeDefinition ranged field construction // since multiple widgets are set on RemotableAttributeField (why?) and it's not possible to determine // lower vs. upper bound settings //} else if (widget instanceof RemotableDatepicker) { // field.setDatePicker(true); } else if (widget instanceof RemotableTextExpand) { field.setExpandedTextArea(true); } } } public static Column constructColumnFromAttributeField(RemotableAttributeField attributeField) { if (attributeField == null) { throw new IllegalArgumentException("attributeField was null"); } DataType dataType = DataType.STRING; if (attributeField.getDataType() != null) { dataType = attributeField.getDataType(); } Column column = new Column(); String columnTitle = ""; if (StringUtils.isBlank(attributeField.getShortLabel())) { if (StringUtils.isBlank(attributeField.getLongLabel())) { columnTitle = attributeField.getName(); } else { columnTitle = attributeField.getLongLabel(); } } else { columnTitle = attributeField.getShortLabel(); } column.setColumnTitle(columnTitle); column.setSortable(Boolean.TRUE.toString()); // TODO - KULRICE-5743 - maybe need this to be smaller than the actual attribute's max length? if (attributeField.getMaxLength() != null) { column.setMaxLength(attributeField.getMaxLength()); } column.setPropertyName(attributeField.getName()); if (attributeField.getDataType() == DataType.MARKUP) { column.setEscapeXMLValue(false); // since the field is a markup type, set the action href column.setColumnAnchor(new AnchorHtmlData()); } else { column.setEscapeXMLValue(true); } column.setComparator(CellComparatorHelper.getAppropriateComparatorForPropertyClass(dataType.getType())); column.setValueComparator( CellComparatorHelper.getAppropriateValueComparatorForPropertyClass(dataType.getType())); if (StringUtils.isNotEmpty(attributeField.getFormatterName())) { try { column.setFormatter(Formatter.getFormatter(Class.forName(attributeField.getFormatterName()))); } catch (ClassNotFoundException e) { LOG.error("Unable to find formatter class: " + attributeField.getFormatterName()); // Fall back to datatype based formatter column.setFormatter(FieldUtils.getFormatterForDataType(dataType)); } } else { column.setFormatter(FieldUtils.getFormatterForDataType(dataType)); } return column; } public static List<Column> constructColumnsFromAttributeFields(List<RemotableAttributeField> attributeFields) { List<Column> attributeColumns = new ArrayList<Column>(); if (attributeFields != null) { for (RemotableAttributeField attributeField : attributeFields) { attributeColumns.add(constructColumnFromAttributeField(attributeField)); } } return attributeColumns; } public static Formatter getFormatterForDataType(DataType dataType) { return Formatter.getFormatter(dataType.getType()); } /** * Finds a container field's sub tab name * * @param field the field for which to derive the collection sub tab name * @return the sub tab name */ public static String generateCollectionSubTabName(Field field) { final String containerName = field.getContainerElementName(); final String cleanedContainerName = (containerName == null) ? "" : containerName.replaceAll("\\d+", ""); StringBuilder subTabName = new StringBuilder(cleanedContainerName); if (field.getContainerDisplayFields() != null) { for (Field containerField : field.getContainerDisplayFields()) { subTabName.append(containerField.getPropertyValue()); } } return subTabName.toString(); } private static Map<String, String> toMap(String s) { if (StringUtils.isBlank(s)) { return Collections.emptyMap(); } final Map<String, String> map = new HashMap<String, String>(); for (String string : s.split(",")) { String[] keyVal = string.split(":"); map.put(keyVal[0], keyVal[1]); } return Collections.unmodifiableMap(map); } private static DataDictionaryService getDataDictionaryService() { if (dataDictionaryService == null) { dataDictionaryService = KRADServiceLocatorWeb.getDataDictionaryService(); } return dataDictionaryService; } private static BusinessObjectMetaDataService getBusinessObjectMetaDataService() { if (businessObjectMetaDataService == null) { businessObjectMetaDataService = KNSServiceLocator.getBusinessObjectMetaDataService(); } return businessObjectMetaDataService; } private static BusinessObjectDictionaryService getBusinessObjectDictionaryService() { if (businessObjectDictionaryService == null) { businessObjectDictionaryService = KNSServiceLocator.getBusinessObjectDictionaryService(); } return businessObjectDictionaryService; } private static KualiModuleService getKualiModuleService() { if (kualiModuleService == null) { kualiModuleService = KRADServiceLocatorWeb.getKualiModuleService(); } return kualiModuleService; } }