/** * Return the relation with name "id" if it can be applied to this component. * * <p>A relation D can be applied on a component source if D.Id == id D.source must be the name of * source or of an ancestor of source, and D.SourceKind == source.getKind. * * <p>Looks in the group, and then in the composite type, if source in an instance in all * composite types if source is an implem. * * @param source * @param id * @return */ @Override public RelationDefinition getRelation(String id) { RelationDefinition dep = null; Component group = this; while (group != null) { dep = ((ComponentImpl) group).getLocalRelation(id); if (dep != null) { return dep; } group = group.getGroup(); } // Looking for composite definitions. if (this instanceof Instance) { CompositeType comptype = ((Instance) this).getComposite().getCompType(); dep = comptype.getCtxtRelation(this, id); if (dep != null) { return dep; } } if (this instanceof Implementation) { for (CompositeType comptype : ((Implementation) this).getInCompositeType()) { dep = comptype.getCtxtRelation(this, id); if (dep != null) { return dep; } } } return null; }
/** Warning : do not resolve ! */ @Override public Set<Link> getRawLinks() { Set<Link> allLinks = new HashSet<Link>(); Component group = this; while (group != null) { allLinks.addAll(((ComponentImpl) group).getLocalLinks()); group = group.getGroup(); } return allLinks; }
/** Whether this component is an ancestor of the specified component */ @Override public boolean isAncestorOf(Component member) { assert member != null; Component ancestor = member.getGroup(); while (ancestor != null && !ancestor.equals(this)) { ancestor = ancestor.getGroup(); } return ancestor != null; }
/** * Return the first link having this name, on any ancestor, but do not try to resolve is none are * found * * @param relName * @return */ public Link getExistingLink(String relName) { Component group = this; while (group != null) { for (Link link : ((ComponentImpl) group).getLocalLinks()) { if (link.getName().equals(relName)) { return link; } } group = group.getGroup(); } return null; }
/** * Return all the link of that names, but do not resolve if nore are found * * @param relName * @return */ public Set<Link> getExistingLinks(String relName) { Set<Link> dests = new HashSet<Link>(); Component group = this; while (group != null) { for (Link link : ((ComponentImpl) group).getLocalLinks()) { if (link.getName().equals(relName)) { dests.add(link); } } group = group.getGroup(); } return dests; }
@Override public boolean setLink(Component destInst, String depName) { /* * Propagate down the group hierarchy. * * TODO Should we stop in case of a veto from one of the members? */ for (Component member : apamComponent.getMembers()) { member.getApformComponent().setLink(destInst, depName); } return true; }
@Override public Set<ResourceReference> getProvidedResources() { Set<ResourceReference> provided = new HashSet<ResourceReference>(); /* * add all provided resources declared at all levels of abstraction */ Component ancestor = this; while (ancestor != null) { provided.addAll(ancestor.getDeclaration().getProvidedResources()); ancestor = ancestor.getGroup(); } return Collections.unmodifiableSet(provided); }
/** * Tries to find the definition of attribute "attr" associated with component "component". Returns * null if the attribute is not explicitly defined * * @param component * @param attr * @return */ public PropertyDefinition getAttrDefinition(String attr) { // PropertyDefinition definition = // getDeclaration().getPropertyDefinition(attr); // if (definition != null) { // return definition; // } PropertyDefinition definition = null; Component group = this; // .getGroup(); while (group != null) { definition = group.getDeclaration().getPropertyDefinition(attr); if (definition != null) { return definition; } group = group.getGroup(); } return null; }
@Override public Set<RelationDefinition> getRelations() { Set<RelationDefinition> relDefs = new HashSet<RelationDefinition>(); Set<String> processed = new HashSet<String>(); Component group = this; while (group != null) { for (RelationDefinition relDef : group.getLocalRelations()) { if (!processed.contains(relDef.getName())) { relDefs.add(relDef); processed.add(relDef.getName()); } } group = group.getGroup(); } // Looking for composite definitions. if (this instanceof Instance) { CompositeType comptype = ((Instance) this).getComposite().getCompType(); for (RelationDefinition relDef : comptype.getCtxtRelations(this)) { if (!processed.contains(relDef.getName())) { relDefs.add(relDef); processed.add(relDef.getName()); } } } if (this instanceof Implementation) { for (CompositeType comptype : ((Implementation) this).getInCompositeType()) { for (RelationDefinition relDef : comptype.getCtxtRelations(this)) { if (!processed.contains(relDef.getName())) { relDefs.add(relDef); processed.add(relDef.getName()); } } } } return relDefs; }
/** * Given a relation declared in this component, checks if the provided override relation matches * the relation declaration. * * <p>To be applied on a component C, the override must be such that : id matches the override id * source must be the name of C or of an ancestor of C. target must be the same type (resource of * component, and its name must match). */ public boolean matchOverride(RelationDeclaration relation, RelationDeclaration override) { // Overrides are currently only valid for instance boolean match = (this instanceof Instance); if (!match) { return false; } // Check if override source matches this component or one of its // ancestors match = false; Component group = this; while (group != null && !match) { match = override.refines(group.getDeclaration().getReference(), relation); group = group.getGroup(); } return match; }
@Override public Link getLink(String relName) { Component group = this; while (group != null) { for (Link link : ((ComponentImpl) group).getLocalLinks()) { if (link.getName().equals(relName)) { return link; } } group = group.getGroup(); } // None are present. Try to resolve RelationDefinition rel = getRelation(relName); if (rel == null) { logger.error("relation " + relName + " undefined for " + this); return null; } Component source = rel.getRelSource(this); CST.apamResolver.resolveLink(source, rel); return getExistingLink(relName); }
/** * 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()); } } }
/** * Provided a component, compute its effective relations definition, adding group constraint and * flags. It is supposed to be correct !! No failure expected * * <p>Does not add those dependencies defined "above". For relations refined locally, merge the * local definition with the group definition. * * <p>For instances only, add the relation definition overridden by the composite. * * <p>Remove those links that are not valid with the computed relation definition (for * changeOwner) */ private void initializeRelations() { /* * First we need to compute the list of relations that must be locally * defined in this component. We consider locally defined relation * declarations and overridden inherited relations. */ Set<RelationDeclaration> overrides = null; if (this instanceof Instance) { overrides = ((Instance) this) .getComposite() .getCompType() .getCompoDeclaration() .getOverridenDependencies(); } else overrides = Collections.emptySet(); Set<RelationDeclaration> localRelations = new HashSet<RelationDeclaration>(); Set<String> processed = new HashSet<String>(); Component group = this; while (group != null) { for (RelationDeclaration relationDeclaration : group.getDeclaration().getRelations()) { /* * Ignore relations already processed at a lower level */ if (processed.contains(relationDeclaration.getIdentifier())) { continue; } /* * Check overridden relations */ boolean matchOverride = false; for (RelationDeclaration override : overrides) { // for (RelationDeclaration override : overrides != null ? overrides // : Collections.<RelationDeclaration> emptySet()) { if (matchOverride(relationDeclaration, override)) { relationDeclaration = relationDeclaration.overriddenBy(override); matchOverride = true; } } /* * Process locally declared and inherited overridden relations */ if (group == this || matchOverride) { localRelations.add(relationDeclaration); processed.add(relationDeclaration.getIdentifier()); } } group = group.getGroup(); } /* * Define all the local relations definition of this component */ for (RelationDeclaration relationDeclaration : localRelations) { /* * Local declarations may be partial definitions, we need to compute * the complete declaration by refining the ancestor definition. */ RelationDefinition base = this.getRelation(relationDeclaration.getIdentifier()); relationDeclaration = (base == null) ? relationDeclaration : ((RelationDefinitionImpl) base).refinedBy(relationDeclaration); relDef.put( relationDeclaration.getIdentifier(), new RelationDefinitionImpl(relationDeclaration)); } /* * If the component has links, remove those that are invalid (for changeOwner) * Also remove the link if it is a promotion, since we are no longer in the same composite */ for (Link localLink : getLocalLinks()) { if (localLink.isPromotion() || !localLink.isValid()) localLink.remove(); } for (Link incoming : getInvLinks()) { if (incoming.isPromotion() || !incoming.isValid()) incoming.remove(); } }
@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; }
/** TODO Assumes that all components are in the same name space, including instance !! */ @Override public int compareTo(Component that) { return this.getName().compareTo(that.getName()); }
/** Whether this component is a descendant of the specified component */ @Override public boolean isDescendantOf(Component group) { assert group != null; return group.isAncestorOf(this); }