@Override
 public Map<String, String> getAllPropertiesString() {
   Map<String, String> ret = new HashMap<String, String>();
   for (Entry<String, Object> e : this.entrySet()) {
     if (!Attribute.isFinalAttribute(e.getKey())) {
       ret.put(e.getKey(), Util.toStringAttrValue(e.getValue()));
     }
   }
   return ret;
 }
 @Override
 public AttrType getAttrType(String attr) {
   PropertyDefinition attrDef = getAttrDefinition(attr);
   if (attrDef == null) {
     if (Attribute.isFinalAttribute(attr)) {
       return Attribute.splitType("string");
     }
     return null;
   }
   return Attribute.splitType(attrDef.getType());
 }
  /**
   * An attribute is valid if declared in an ancestor, and not set in an ancestor. Check if the
   * value is conforming to its type (string, int, boolean). Internal attribute (associated with a
   * field) cannot be set. Must be called on the level above.
   *
   * <p>Checks if attr is correctly defined for component ent it must be explicitly defined in its
   * upper groups, for the top group, it must be already existing.
   *
   * <p>boolean Forced = true can be set only by Apform. Needed when an internal attribute is set in
   * the program, Apform propagates the value to the attribute.
   *
   * @param attr
   * @param value
   * @return
   */
  public PropertyDefinition validDef(String attr, boolean forced) {
    if (Attribute.isFinalAttribute(attr)) {
      logger.error("In " + this + ", cannot redefine final attribute \"" + attr + "\"");
      return null;
    }

    if (Attribute.isReservedAttributePrefix(attr)) {
      logger.error("In " + this + ", attribute\"" + attr + "\" is reserved");
      return null;
    }

    PropertyDefinition definition = this.getAttrDefinition(attr);
    if (definition == null) {
      logger.error("In " + this + ", attribute \"" + attr + "\" is undefined.");
      return null;
    }

    /*
     * Internal field attributes cannot be set
     */
    if (definition.getInjected() == InjectedPropertyPolicy.INTERNAL && !forced) {
      logger.error(
          "In "
              + this
              + ", attribute \""
              + attr
              + "\" is an internal field attribute and cannot be set.");
      return null;
    }

    /*
     * if the same attribute exists above, it is a redefinition.
     */
    ComponentImpl group = (ComponentImpl) this.getGroup();
    if (group != null && group.get(attr) != null) {

      Object groupValue = group.get(attr);
      String defaultValue = definition.getDefaultValue();

      boolean isDefault =
          defaultValue != null
              && groupValue.equals(
                  Attribute.checkAttrType(attr, defaultValue, definition.getType()));

      // If the attribute above is the default value, it is allowed to change it
      if (!isDefault && !Attribute.isBuiltAttribute(attr)) {
        logger.error("In " + this + ", cannot redefine attribute \"" + attr + "\"");
        return null;
      }
    }

    return definition;
  }
  /**
   * Warning: to be used only by Apform for removing internal attributes. Only Inhibits the message
   * "Attribute " + attr + " is an program field attribute and cannot be removed.");
   */
  public boolean removeProperty(String attr, boolean forced) {

    String oldValue = getProperty(attr);

    if (oldValue == null) {
      logger.error("ERROR: \"" + attr + "\" not instanciated");
      return false;
    }

    if (Attribute.isFinalAttribute(attr)) {
      logger.error("ERROR: \"" + attr + "\" is a final attribute");
      return false;
    }

    if (Attribute.isReservedAttributePrefix(attr)) {
      logger.error("ERROR: \"" + attr + "\" is a reserved attribute");
      return false;
    }

    PropertyDefinition propDef = getAttrDefinition(attr);
    if (propDef != null && propDef.getField() != null && !forced) {
      logger.error(
          "In " + this + " attribute " + attr + " is a program field and cannot be removed.");
      return false;
    }

    if (getGroup() != null && getGroup().getProperty(attr) != null) {
      logger.error("In " + this + " attribute " + attr + " inherited and cannot be removed.");
      return false;
    }

    // it is ok, remove it and propagate to members, recursively
    propagateRemove(attr);

    // TODO. Should we notify at all levels ?
    ApamManagers.notifyAttributeRemoved(this, attr, oldValue);

    return true;
  }