/**
  * Orders attributes by defined order.
  *
  * <p>First looks to see if attributes are inherited, then looks at the declared fields based on
  * the attribute type.
  *
  * @param attributes list of data object attributes
  * @return re-ordered list of data object attributes
  */
 public List<DataObjectAttribute> orderAttributesByDefinedOrder(
     List<DataObjectAttribute> attributes) {
   List<DataObjectAttribute> sorted = new ArrayList<DataObjectAttribute>(attributes.size());
   Map<String, DataObjectAttribute> keyedAttributes =
       new HashMap<String, DataObjectAttribute>(attributes.size());
   Map<String, List<DataObjectAttribute>> inheritedAttributes =
       new HashMap<String, List<DataObjectAttribute>>();
   for (DataObjectAttribute attr : attributes) {
     if (attr.isInherited()) {
       List<DataObjectAttribute> inheritedByProperty =
           inheritedAttributes.get(attr.getInheritedFromParentAttributeName());
       if (inheritedByProperty == null) {
         inheritedByProperty = new ArrayList<DataObjectAttribute>();
         inheritedAttributes.put(attr.getInheritedFromParentAttributeName(), inheritedByProperty);
       }
       inheritedByProperty.add(attr);
     } else {
       keyedAttributes.put(attr.getName(), attr);
     }
   }
   for (Field f : getType().getDeclaredFields()) {
     DataObjectAttribute attr = keyedAttributes.get(f.getName());
     if (attr != null) {
       sorted.add(attr);
       keyedAttributes.remove(f.getName());
     }
     if (inheritedAttributes.containsKey(f.getName())) {
       sorted.addAll(inheritedAttributes.get(f.getName()));
     }
   }
   sorted.addAll(keyedAttributes.values());
   return sorted;
 }
 protected UifDisplayHint getHintOfType(DataObjectAttribute attr, UifDisplayHintType hintType) {
   if (attr != null && attr.getDisplayHints() != null) {
     for (UifDisplayHint hint : attr.getDisplayHints()) {
       if (hint.value().equals(hintType)) {
         return hint;
       }
     }
   }
   return null;
 }
 /**
  * Sets attributes.
  *
  * <p>Looks at merge actions when adding, so not all attributes are added.
  *
  * @param attributes list of data object attributes
  */
 public void setAttributes(List<DataObjectAttribute> attributes) {
   if (attributes == null) {
     attributes = Collections.emptyList();
   }
   this.attributes = Collections.unmodifiableList(attributes);
   mergedAttributes = null;
   attributeMap = new HashMap<String, DataObjectAttribute>(attributes.size());
   removedAttributeNames = new ArrayList<String>();
   for (DataObjectAttribute attr : attributes) {
     // TODO: This is not quite correct - we really only want to not add the NO_OVERRIDE items if
     // they are
     // overriding something. However, at the point this is running, we don't know whether we will
     // be embedding
     // anything...
     if (attr.getMergeAction() != MetadataMergeAction.REMOVE
         && attr.getMergeAction() != MetadataMergeAction.NO_OVERRIDE) {
       attributeMap.put(attr.getName(), attr);
     }
     // since the attribute will still exist in the embedded metadata, we need to put a block in on
     // the standard
     // cascade
     if (attr.getMergeAction() == MetadataMergeAction.REMOVE) {
       removedAttributeNames.add(attr.getName());
     }
   }
 }
 /** {@inheritDoc} */
 @Override
 public DataObjectAttribute getAttribute(String attributeName) {
   if (attributeName == null) {
     return null;
   }
   DataObjectAttribute attribute = null;
   // attempt to get it from the local attribute map (if any attributed defined locally)
   if (attributes != null) {
     attribute = attributeMap.get(attributeName);
   }
   // if we don't find one, but we have an embedded metadata object, check it
   if (attribute == null && embedded != null) {
     attribute = embedded.getAttribute(attributeName);
     // but, ensure it's not on the removed attribute list
     if (attribute != null
         && removedAttributeNames != null
         && removedAttributeNames.contains(attribute.getName())) {
       attribute = null;
     }
   }
   return attribute;
 }
 protected Control getControlInstance(
     AttributeDefinition attrDef, DataObjectAttribute dataObjectAttribute) {
   Control c = null;
   // Check for the hidden hint - if present - then use that control type
   if (dataObjectAttribute != null
       && hasHintOfType(dataObjectAttribute, UifDisplayHintType.HIDDEN)) {
     c = ComponentFactory.getHiddenControl();
   } else if (attrDef.getOptionsFinder() != null) {
     // if a values finder has been established, use a radio button group or drop-down list
     if (dataObjectAttribute != null
         && hasHintOfType(dataObjectAttribute, UifDisplayHintType.RADIO)) {
       c = ComponentFactory.getRadioGroupControl();
     } else {
       c = ComponentFactory.getSelectControl();
     }
   } else if (attrDef.getName().endsWith(".principalName") && dataObjectAttribute != null) {
     // FIXME: JHK: Yes, I know this is a *HORRIBLE* hack - but the alternative
     // would look even more "hacky" and error-prone
     c = ComponentFactory.getUserControl();
     // Need to find the relationship information
     // get the relationship ID by removing .principalName from the attribute name
     String relationshipName = StringUtils.removeEnd(attrDef.getName(), ".principalName");
     DataObjectMetadata metadata =
         dataObjectService
             .getMetadataRepository()
             .getMetadata(dataObjectAttribute.getOwningType());
     if (metadata != null) {
       DataObjectRelationship relationship = metadata.getRelationship(relationshipName);
       if (relationship != null
           && CollectionUtils.isNotEmpty(relationship.getAttributeRelationships())) {
         ((UserControl) c)
             .setPrincipalIdPropertyName(
                 relationship.getAttributeRelationships().get(0).getParentAttributeName());
         ((UserControl) c)
             .setPersonNamePropertyName(
                 relationshipName + "." + KimConstants.AttributeConstants.NAME);
         ((UserControl) c).setPersonObjectPropertyName(relationshipName);
       }
     } else {
       LOG.warn(
           "Attempt to pull relationship name: "
               + relationshipName
               + " resulted in missing metadata when looking for: "
               + dataObjectAttribute.getOwningType());
     }
   } else {
     switch (attrDef.getDataType()) {
       case STRING:
         // TODO: Determine better way to store the "200" metric below
         if (attrDef.getMaxLength() != null && attrDef.getMaxLength().intValue() > 200) {
           c = ComponentFactory.getTextAreaControl();
         } else {
           c = ComponentFactory.getTextControl();
         }
         break;
       case BOOLEAN:
         c = ComponentFactory.getCheckboxControl();
         break;
       case DATE:
       case DATETIME:
       case TRUNCATED_DATE:
         c = ComponentFactory.getDateControl();
         break;
       case CURRENCY:
       case DOUBLE:
       case FLOAT:
       case INTEGER:
       case LARGE_INTEGER:
       case LONG:
       case PRECISE_DECIMAL:
         c = ComponentFactory.getTextControl();
         break;
       case MARKUP:
         c = ComponentFactory.getTextAreaControl();
         break;
       default:
         c = ComponentFactory.getTextControl();
         break;
     }
   }
   return c;
 }