/** * 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; }
/** * 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); } }
/** * TODO. Should we notify at all levels ? * * @param ent * @param attr */ private void propagateRemove(String attr) { remove(attr); for (Component member : getMembers()) { ((ComponentImpl) member).propagateRemove(attr); } }
/** * To be called once the Apam entity is fully initialized. * * <p>Computes all its attributes, including inheritance. Checks if initial properties are * consistent with the declarations. * * <p>NOTE this method is also called when the owner changes, to force recalculation of * substitutions that depend on the current owner. */ private void initializeProperties(Map<String, String> initialProperties) { Component group = getGroup(); /* * Currently the instance declaration may include invalid properties. * * For declared instances this should not happen as the declaration is validated at build-time. For dynamically * created instances (using the APAM API or the apform API directly) this should be validated by this method. * * However, there are many properties added by the iPOJO apform layer that need to be ignored, so we simply * silently ignore all invalid properties. * * TODO We should be able to distinguish properties specified by the user that must be validated, from properties * used internally by the iPOJO apform. */ Set<String> invalidDeclaredProperties = new HashSet<String>(); for (String property : getDeclaration().getProperties().keySet()) { boolean isDefined = getDeclaration().isDefined(property) || (group != null && group.getPropertyDefinition(property) != null); if (!isDefined) { invalidDeclaredProperties.add(property); } if (group != null && group.getProperty(property) != null) { invalidDeclaredProperties.add(property); } } getDeclaration().getProperties().keySet().removeAll(invalidDeclaredProperties); /* * Merge initial and declared properties. * */ Map<String, String> fullInitialProperties = new HashMap<String, String>(getDeclaration().getProperties()); if (initialProperties != null) { fullInitialProperties.putAll(initialProperties); fullInitialProperties.remove("instance.name"); } /* * NOTE In the case of change owner, the initial properties include inherited values from the group, * we ignore them to avoid false error messages, they will be added later by the normal inheritance * mechanism * * TODO Distinguish the case of change owner from a real initialization */ if (initialProperties != null && group != null) { for (Map.Entry<String, String> initialProperty : initialProperties.entrySet()) { if (group.getProperty(initialProperty.getKey()) != null && group.getProperty(initialProperty.getKey()).equals(initialProperty.getValue())) { fullInitialProperties.remove(initialProperty.getKey()); } } } // start cleaning the properties (normally empty) clear(); /* * First add the valid attributes. */ for (Map.Entry<String, String> initialProperty : fullInitialProperties.entrySet()) { PropertyDefinition def = validDef(initialProperty.getKey(), true); if (def != null) { Object val = Attribute.checkAttrType( initialProperty.getKey(), initialProperty.getValue(), def.getType()); if (val != null) { put(initialProperty.getKey(), val); } } } /* * then add those coming from its group, avoiding overloads. */ if (group != null) { for (String attr : group.getAllProperties().keySet()) { if (get(attr) == null) { put(attr, ((ComponentImpl) group).get(attr)); } } } /* * Add the default values specified in the group for properties not explicitly specified */ if (group != null) { for (PropertyDefinition definition : group.getDeclaration().getPropertyDefinitions()) { if (definition.hasDefaultValue() && get(definition.getName()) == null && definition.getInjected() != InjectedPropertyPolicy.INTERNAL) { Object val = Attribute.checkAttrType( definition.getName(), definition.getDefaultValue(), definition.getType()); if (val != null) { put(definition.getName(), val); } } } } /* * Set the attribute for the final attributes */ put(CST.SHARED, Boolean.toString(isShared())); put(CST.SINGLETON, Boolean.toString(isSingleton())); put(CST.INSTANTIABLE, Boolean.toString(isInstantiable())); /* * Finally add the specific attributes. * Should be the only place where instanceof is used. */ put(CST.NAME, apform.getDeclaration().getName()); if (this instanceof Specification) { put(CST.SPECNAME, apform.getDeclaration().getName()); } else if (this instanceof Implementation) { put(CST.IMPLNAME, apform.getDeclaration().getName()); if (this instanceof CompositeType) { put(CST.APAM_COMPOSITETYPE, CST.V_TRUE); } } else if (this instanceof Instance) { put(CST.INSTNAME, apform.getDeclaration().getName()); if (this instanceof Composite) { Composite composite = (Composite) this; put(CST.APAM_COMPOSITE, CST.V_TRUE); if (composite.getMainInst() != null) { put(CST.APAM_MAIN_INSTANCE, composite.getMainInst().getName()); } } } /* * and propagate, to the platform and to members, in case the spec has been created after the implem */ for (Map.Entry<String, Object> entry : this.entrySet()) { for (Component member : getMembers()) { ((ComponentImpl) member).propagate(entry.getKey(), entry.getValue()); } } }
@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; }