package fr.imag.adele.apam.impl; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import fr.imag.adele.apam.CST; import fr.imag.adele.apam.Component; import fr.imag.adele.apam.Implementation; import fr.imag.adele.apam.Instance; import fr.imag.adele.apam.RelationDefinition; import fr.imag.adele.apam.Specification; import fr.imag.adele.apam.declarations.ComponentKind; import fr.imag.adele.apam.declarations.CreationPolicy; import fr.imag.adele.apam.declarations.MissingPolicy; import fr.imag.adele.apam.declarations.RelationDeclaration; import fr.imag.adele.apam.declarations.RequirerInstrumentation; import fr.imag.adele.apam.declarations.ResolvePolicy; import fr.imag.adele.apam.declarations.references.ResolvableReference; import fr.imag.adele.apam.declarations.references.components.ComponentReference; import fr.imag.adele.apam.declarations.references.components.ImplementationReference; import fr.imag.adele.apam.declarations.references.components.SpecificationReference; import fr.imag.adele.apam.util.ApamFilter; public class RelationDefinitionImpl implements RelationDefinition { static Logger logger = LoggerFactory.getLogger(ApamResolverImpl.class); /** * The effective declaration used to build this relation, */ private final RelationDeclaration declaration; // Relationship name private final String identifier; // Target definition (resource or component reference) private final ResolvableReference targetDefinition; // Source type for this relation (Spec, implem, instance) private final ComponentKind sourceKind; // Target type for this relation (Spec, implem, instance) private final ComponentKind targetKind; // TODO // The reference to the associated component ?? // private final Component component; /** * The set of constraints that must be satisfied by the target component * implementation. Filters are set only if static (i.e. there is no * substitutions into filters) */ private final Set<String> implementationConstraints = new HashSet<String>(); private Set<ApamFilter> implementationConstraintFilters; // = new // HashSet<ApamFilter>(); private boolean isStaticImplemConstraints; /** * The set of constraints that must be satisfied by the target component * instance */ private final Set<String> instanceConstraints = new HashSet<String>(); private Set<ApamFilter> instanceConstraintFilters; // = new // HashSet<ApamFilter>(); private boolean isStaticInstConstraints; /** * The list of preferences to choose among candidate service provider * implementation */ private final List<String> implementationPreferences = new ArrayList<String>(); private List<ApamFilter> implementationPreferenceFilters; // = new // ArrayList<ApamFilter>(); private boolean isStaticImplemPreferences = false; /** * The list of preferences to choose among candidate service provider * instances */ private final List<String> instancePreferences = new ArrayList<String>(); private List<ApamFilter> instancePreferenceFilters; // = new // ArrayList<ApamFilter>(); private boolean isStaticInstPreferences = false; // Whether this relation is declared explicitly as multiple private final boolean isMultiple; private final CreationPolicy create; private final ResolvePolicy resolve; // The policy to handle unresolved dependencies private final MissingPolicy missingPolicy; // The exception to throw for the exception missing policy private final String missingException; // Whether a resolution error must trigger a backtrack in the architecture private final boolean mustHide; // true if this is a dynamic relation : a field multiple, or a dynamic // message private final boolean isDynamic; // If this is a Wire definition. Can be overloaded. Null if unknown. private boolean isWire; // Injected. Can be overloaded. Null if unknown. private boolean isInjected; /* * Component can be null; in that case filters are not substituted. */ public RelationDefinitionImpl(RelationDeclaration declaration) { this.declaration = declaration; this.identifier = declaration.getIdentifier(); this.sourceKind = (declaration.getSourceKind() == null) ? ComponentKind.INSTANCE : declaration.getSourceKind(); this.targetKind = (declaration.getTargetKind() == null) ? ComponentKind.INSTANCE : declaration.getTargetKind(); this.targetDefinition = declaration.getTarget(); // computing isDynamic, isWire, hasField. // NOTE the relation declaration is already refined and overridden so // we have access to all the information from all levels above this.isWire = false; this.isInjected = false; boolean hasCallbacks = false; for (RequirerInstrumentation injection : declaration.getInstrumentations()) { if (injection instanceof RequirerInstrumentation.MessageConsumerCallback) { hasCallbacks = true; } if (injection instanceof RequirerInstrumentation.RequiredServiceField) { this.isInjected = true; if (((RequirerInstrumentation.RequiredServiceField) injection).isWire()) { this.isWire = true; } } } // Flags this.isMultiple = declaration.isMultiple(); if (declaration.getCreationPolicy() == null) { this.create = hasCallbacks ? CreationPolicy.EAGER : CreationPolicy.LAZY; } else { this.create = declaration.getCreationPolicy(); } this.resolve = declaration.getResolvePolicy() == null ? ResolvePolicy.EXTERNAL : declaration.getResolvePolicy(); this.missingPolicy = declaration.getMissingPolicy(); this.missingException = declaration.getMissingException(); this.mustHide = (declaration.isHide() == null) ? false : declaration.isHide(); this.isDynamic = declaration.isMultiple() || (this.create == CreationPolicy.EAGER); // Constraints this.implementationConstraints.addAll(declaration.getImplementationConstraints()); this.instanceConstraints.addAll(declaration.getInstanceConstraints()); this.implementationPreferences.addAll(declaration.getImplementationPreferences()); this.instancePreferences.addAll(declaration.getInstancePreferences()); // Check constraint syntax and compute booleans isStaticxxxx initializeRelation(); } public RelationDefinitionImpl(ResolvableReference target, ComponentKind sourceKind, ComponentKind targetKind, Set<String> constraints, List<String> preferences) { // The minimum info for a find. this.declaration = null; this.identifier = ""; this.targetDefinition = target; this.isMultiple = false; this.create = CreationPolicy.LAZY; this.resolve = ResolvePolicy.EXTERNAL; this.sourceKind = (sourceKind == null) ? ComponentKind.INSTANCE : sourceKind; this.targetKind = (targetKind == null) ? ComponentKind.INSTANCE : targetKind; isDynamic = false; isWire = false; isInjected = false; mustHide = false; missingException = null; missingPolicy = null; if (constraints != null) { if (targetKind == ComponentKind.IMPLEMENTATION) { implementationConstraints.addAll(constraints); } instanceConstraints.addAll(constraints); } if (preferences != null) { if (targetKind == ComponentKind.IMPLEMENTATION) { implementationPreferences.addAll(constraints); } instancePreferences.addAll(preferences); } // Check constraint syntax and compute filter and booleans isStaticxxxx initializeRelation(); } @Override public CreationPolicy getCreation() { return create; } public RelationDeclaration getDeclaration() { return declaration; } public Set<ApamFilter> getImplementationConstraintFilters() { return Collections.unmodifiableSet(implementationConstraintFilters); } /** * Get the constraints that need to be satisfied by the implementation that * resolves the reference */ @Override public Set<String> getImplementationConstraints() { return Collections.unmodifiableSet(implementationConstraints); } // Get the resource provider preferences @Override public List<String> getImplementationPreferences() { return Collections.unmodifiableList(implementationPreferences); } public List<ApamFilter> getImplementationpreferencfeFilters() { return Collections.unmodifiableList(implementationPreferenceFilters); } public Set<ApamFilter> getInstanceConstraintFilters() { return Collections.unmodifiableSet(instanceConstraintFilters); } // Get the constraints that need to be satisfied by the instance that // resolves the reference @Override public Set<String> getInstanceConstraints() { return Collections.unmodifiableSet(instanceConstraints); } public List<ApamFilter> getInstancePreferenceFilters() { return Collections.unmodifiableList(instancePreferenceFilters); } // Get the instance provider preferences @Override public List<String> getInstancePreferences() { return Collections.unmodifiableList(instancePreferences); } // Get the exception associated with the missing policy @Override public String getMissingException() { return missingException; } // Get the policy associated with this relation @Override public MissingPolicy getMissingPolicy() { return missingPolicy; } // Get the id of the relation in the declaring component declaration @Override public String getName() { return identifier; } /* * return the component corresponding to the sourceKind. */ @Override public Component getRelSource(Component base) { Component source = base; while (source != null) { if (source.getKind() == getSourceKind()) { return source; } source = source.getGroup(); } return null; } @Override public ResolvePolicy getResolve() { return resolve; } @Override public ComponentKind getSourceKind() { return sourceKind; } /** * Get the reference to the required resource */ @Override public ResolvableReference getTarget() { return targetDefinition; } @Override public ComponentKind getTargetKind() { return targetKind; } @Override public boolean hasConstraints() { return !implementationConstraints.isEmpty() || !instanceConstraints.isEmpty(); } /** * To be called before any use of this relation. * * @param component * the component source on which is defined this relation */ private void initializeRelation() { // Check if there are substitutions, and build filters ApamFilter f; isStaticImplemConstraints = true; isStaticInstConstraints = true; isStaticImplemPreferences = true; isStaticInstPreferences = true; for (String c : implementationConstraints) { implementationConstraintFilters = new HashSet<ApamFilter>(); if (ApamFilter.isSubstituteFilter(c, null)) { isStaticImplemConstraints = false; implementationConstraintFilters = null; break; } f = ApamFilter.newInstanceApam(c, null); if (f != null) { implementationConstraintFilters.add(f); } } for (String c : instanceConstraints) { instanceConstraintFilters = new HashSet<ApamFilter>(); if (ApamFilter.isSubstituteFilter(c, null)) { isStaticInstConstraints = false; instanceConstraintFilters = null; break; } f = ApamFilter.newInstanceApam(c, null); if (f != null) { instanceConstraintFilters.add(f); } } for (String c : implementationPreferences) { implementationPreferenceFilters = new ArrayList<ApamFilter>(); if (ApamFilter.isSubstituteFilter(c, null)) { isStaticImplemPreferences = false; implementationPreferenceFilters = null; break; } f = ApamFilter.newInstanceApam(c, null); if (f != null) { implementationPreferenceFilters.add(f); } } for (String c : instancePreferences) { instancePreferenceFilters = new ArrayList<ApamFilter>(); if (ApamFilter.isSubstituteFilter(c, null)) { isStaticInstPreferences = false; instancePreferenceFilters = null; break; } f = ApamFilter.newInstanceApam(c, null); if (f != null) { instancePreferenceFilters.add(f); } } } @Override public boolean isDynamic() { return isDynamic; } /** * Whether an error resolving a relation matching this policy should trigger * a backtrack in resolution */ @Override public boolean isHide() { return mustHide; } @Override public boolean isInjected() { return isInjected; } @Override public boolean isMultiple() { return isMultiple; } @Override public boolean isRelation() { return !identifier.isEmpty(); } public boolean isStaticImplemConstraints() { return isStaticImplemConstraints; } public boolean isStaticImplemPreferences() { return isStaticImplemPreferences; } public boolean isStaticInstConstraints() { return isStaticInstConstraints; } public boolean isStaticInstPreferences() { return isStaticInstPreferences; } // return !mngImplementationConstraintFilters.isEmpty() // || !mngInstanceConstraintFilters.isEmpty() // || !implementationConstraintFilters.isEmpty() // || !instanceConstraintFilters.isEmpty(); @Override public boolean isWire() { return isWire; } /** * Provided a client instance, checks if its relation "clientDep", matches * another relation: "compoDep". * * matches only based on same name (same resource or same component). If * client cardinality is multiple, compo cardinallity must be multiple too. * No provision for the client constraints or characteristics (missing, * eager) * * @param compoInst * the composite instance containing the client * @param compoDep * the relation that matches or not * @param clientDep * the client relation we are trying to resolve * @return */ @Override public boolean matchRelation(Instance compoInst, RelationDefinition compoDep) { // RelToResolve rel = new RelToResolveImpl (inst, relDef) ; // return rel.matchRelation(inst) ; // } if (compoDep == null) { return false; } if (compoDep.getTargetKind() != getTargetKind()) { return false; } if (compoDep.getSourceKind() != getSourceKind()) { return false; } // Look for same relation: the same specification, the same // implementation or same resource name // Constraints are not taken into account boolean multiple = isMultiple(); // if same nature (spec, implem, internface ... make a direct // comparison. if (compoDep.getTarget().getClass().equals(getTarget().getClass())) { if (compoDep.getTarget().equals(getTarget())) { if (!multiple || compoDep.isMultiple()) { return true; } } } // Look for a compatible relation. // Stop at the first relation matching only based on same name (same // resource or same component) // No provision for : cardinality, constraints or characteristics // (missing, eager) // Look if the client requires one of the resources provided by the // specification if (compoDep.getTarget() instanceof SpecificationReference) { Specification spec = CST.apamResolver.findSpecByName(compoInst, ((SpecificationReference) compoDep.getTarget()).getName()); if ((spec != null) && spec.getDeclaration().getProvidedResources().contains(getTarget()) && (!multiple || compoDep.isMultiple())) { return true; } } // If the composite has a relation toward an implementation // and the client requires a resource provided by that implementation else { if (compoDep.getTarget() instanceof ImplementationReference) { String implName = ((ImplementationReference<?>) compoDep.getTarget()).getName(); Implementation impl = CST.apamResolver.findImplByName(compoInst, implName); if (impl != null) { // The client requires the specification implemented by that // implementation if (getTarget() instanceof SpecificationReference) { String clientReqSpec = ((SpecificationReference) getTarget()).getName(); if (impl.getSpec().getName().equals(clientReqSpec) && (!multiple || compoDep.isMultiple())) { return true; } } else { // The client requires a resource provided by that // implementation if (impl.getImplDeclaration().getProvidedResources().contains(getTarget()) && (!multiple || compoDep.isMultiple())) { return true; } } } } } return false; } // public static LinkImpl createLink () /** * Checks if this relation can refine the specified declaration for refinement or override. * Matching can be based on the name of the declaring component or one of its ancestor groups * */ public boolean refines(ComponentReference<?>group, RelationDeclaration relation) { return this.declaration != null ? this.declaration.refines(group,relation) : false; } /** * Checks if this contextual relation definition applies to the specified source */ public boolean appliesTo(ComponentReference<?> source) { return this.declaration != null ? this.declaration.appliesTo(source) : false; } /** * Get the effective result of refining this relation by the specified partial declaration */ public RelationDeclaration refinedBy(RelationDeclaration refinement) { return this.declaration != null ? this.declaration.refinedBy(refinement) : refinement; } @Override public String toString() { StringBuffer ret = new StringBuffer(); // ret.append("resolving "); if (isRelation()) { ret.append("relation " + getName() + " towards "); } if (isMultiple) { ret.append("multiple "); } ret.append(getTargetKind()); if (getTarget() instanceof ComponentReference<?>) { ret.append(" of" + getTarget()); } else { ret.append(" providing " + getTarget()); } // ret.append(" from " + linkSource); ret.append(" (creation = " + create + ", resolve = " + resolve + ", missing policy = " + this.missingPolicy + ")"); return ret.toString(); } }