/**
   * set the value, update apform and the platform, notify managers and propagates to the members,
   * recursively
   *
   * @param com the component on which ot set the attribute
   * @param attr attribute name
   * @param value attribute value
   */
  private void propagate(String attr, Object value) {
    if (value == null) {
      return;
    }
    Object oldValue = get(attr);
    if (oldValue != null && oldValue.equals(value.toString())) {
      return;
    }

    // Change value
    put(attr, value);

    // Notify the execution platform
    if (get(attr) == value) {
      getApformComponent().setProperty(attr, value.toString());
    }

    /*
     * notify property managers
     */
    if (oldValue == null) {
      ApamManagers.notifyAttributeAdded(this, attr, value.toString());
    } else {
      ApamManagers.notifyAttributeChanged(this, attr, value.toString(), oldValue.toString());
    }

    // Propagate to members recursively
    for (Component member : getMembers()) {
      ((ComponentImpl) member).propagate(attr, value);
    }
  }
  /**
   * 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;
  }
  @Override
  public boolean createLink(
      Component to, RelToResolve dep, boolean hasConstraints, boolean promotion) {
    // Not a relation : a find
    if (!dep.isRelation()) {
      return true;
    }

    if (CST.isFinalRelation(dep.getName())) {
      logger.error("CreateLink: cannot create predefined relation " + dep.getName());
      return false;
    }

    if ((to == null) || (dep == null)) {
      logger.error("CreateLink: Source or target are null ");
      return false;
    }

    if (!promotion && !canSee(to)) {
      logger.error("CreateLink: Source  " + this + " does not see its target " + to);
      return false;
    }

    if (this.getKind() != dep.getSourceKind()) {
      logger.error(
          "CreateLink: Source kind "
              + getKind()
              + " is not compatible with relation sourceType "
              + dep.getSourceKind());
      return false;
    }

    if (to.getKind() != dep.getTargetKind()) {
      logger.error(
          "CreateLink: Target kind "
              + to.getKind()
              + " is not compatible with relation targetType "
              + dep.getTargetKind());
      return false;
    }

    if (hasConstraints && !dep.matchRelationConstraints(to)) {
      logger.error("CreateLink: Target does not satisfies the constraints");
      return false;
    }

    String depName = dep.getName();

    for (Link link : links) { // check if it already exists
      if ((link.getDestination() == to) && link.getName().equals(depName)) {
        // It exists, do nothing.
        return true;
      }
    }

    // creation
    if (!getApformComponent().checkLink(to, depName)) {
      logger.error(
          "CreateLink: INTERNAL ERROR: link from "
              + this
              + " to "
              + to
              + " could not be created in the real instance.");
      return false;
    }

    Link link = new LinkImpl(this, to, dep, hasConstraints, promotion);
    links.add(link);
    ((ComponentImpl) to).invlinks.add(link);
    getApformComponent().setLink(to, depName);

    // Notify Dynamic managers that a new link has been created
    for (DynamicManager manager : ApamManagers.getDynamicManagers()) {
      manager.addedLink(link);
    }

    return true;
  }