Package fr.imag.adele.apam.impl

Source Code of fr.imag.adele.apam.impl.RelToResolveImpl

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.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import fr.imag.adele.apam.Component;
import fr.imag.adele.apam.Implementation;
import fr.imag.adele.apam.Instance;
import fr.imag.adele.apam.RelToResolve;
import fr.imag.adele.apam.RelationDefinition;
import fr.imag.adele.apam.Resolved;
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.ResolvePolicy;
import fr.imag.adele.apam.declarations.references.ResolvableReference;
import fr.imag.adele.apam.declarations.references.components.ComponentReference;
import fr.imag.adele.apam.util.ApamFilter;

public class RelToResolveImpl implements RelToResolve {

  static Logger logger = LoggerFactory.getLogger(ApamResolverImpl.class);

  /**
   * Return the "best" component among the candidates. Best depends on the
   * component nature. For implems, it is those that have sharable instance or
   * that is instantiable.
   *
   * @param <T>
   * @param candidates
   * @return
   */
  private static <T extends Component> T getDefaultComponent(Set<T> candidates) {
    if (candidates == null || candidates.isEmpty()) {
      return null;
    }
    if (!(candidates.iterator().next() instanceof Implementation)) {
      return candidates.iterator().next();
    }

    for (T impl : candidates) {
      if (impl.isInstantiable()) {
        return impl;
      }
      for (Component inst : impl.getMembers()) {
        if (((Instance) inst).isSharable()) {
          return impl;
        }
      }
    }
    return candidates.iterator().next();
  }

  private static <T extends Component> T getPreferedFilter(Set<T> candidates, List<ApamFilter> preferences) {
    if (preferences.isEmpty()) {
      return getDefaultComponent(candidates);
    }

    Set<T> valids = new HashSet<T>();
    for (ApamFilter f : preferences) {
      for (T compo : candidates) {
        if (compo.match(f)) {
          valids.add(compo);
        }
      }

      // If a single one satisfies, it is the prefered one.
      if (valids.size() == 1) {
        return valids.iterator().next();
      }

      // If nobody satisfies the contraints check next constraint with
      // same set of candidates
      if (valids.isEmpty()) {
        break;
      }

      // continue with those that satisfy the constraint
      candidates = valids;
      valids = new HashSet<T>();
    }

    // More than one candidate are still here: return the default one.
    return getDefaultComponent(candidates);
  }

  // The actual source of this relation. Set just before a resolution
  private final Component linkSource;

  // The associated relation definition.
  private final RelationDefinition relationDefinition;
  // this relation was created but never computed so far. bool isStaticxyz are
  // not set yet
  private boolean isInitialized = false;

  /**
   * The set of constraints that must be satisfied by the target component
   * implementation The intrinsic ones, then those added by managers (maybe).
   */
  private Set<String> mngImplementationConstraints = new HashSet<String>();
  private Set<ApamFilter> allImplementationConstraintFilters = new HashSet<ApamFilter>();

  /**
   * The set of constraints that must be satisfied by the target component
   * instance
   */
  private Set<String> mngInstanceConstraints = new HashSet<String>();
  private Set<ApamFilter> allInstanceConstraintFilters = new HashSet<ApamFilter>();

  /**
   * The list of preferences to choose among candidate service provider
   * implementation
   */
  private List<String> mngImplementationPreferences = new ArrayList<String>();
  private List<ApamFilter> allImplementationPreferenceFilters = new ArrayList<ApamFilter>();

  /**
   * The list of preferences to choose among candidate service provider
   * instances
   */
  private List<String> mngInstancePreferences = new ArrayList<String>();
  private List<ApamFilter> allInstancePreferenceFilters = new ArrayList<ApamFilter>();

  /*
   * Component can be null; in that case filters are not substituted.
   */
  public RelToResolveImpl(Component source, RelationDeclaration declaration) {
    relationDefinition = new RelationDefinitionImpl(declaration);
    linkSource = source;
  }

  public RelToResolveImpl(Component source, RelationDefinition relation) {
    relationDefinition = relation;
    linkSource = source;
  }

  public RelToResolveImpl(Component source, ResolvableReference target, ComponentKind sourceKind, ComponentKind targetKind, Set<String> constraints, List<String> preferences) {
    // The minimum info for a find.
    relationDefinition = new RelationDefinitionImpl(target, sourceKind, targetKind, constraints, preferences);
    linkSource = source;
  }

  /**
   * Called after the managers have added their constraints, and before to try
   * to resolve that relation. First it clears the previous filters (except if
   * immutable), and recompute them from the string contraints Adds in mng the
   * preferences and constraints filters
   */
  public void computeFilters() {

    isInitialized = true;
    ApamFilter f;

    for (String c : mngImplementationConstraints) {
      f = ApamFilter.newInstanceApam(c, linkSource);
      if (f != null) {
        allImplementationConstraintFilters.add(f);
      }
    }

    for (String c : mngInstanceConstraints) {
      f = ApamFilter.newInstanceApam(c, linkSource);
      if (f != null) {
        allInstanceConstraintFilters.add(f);
      }
    }

    for (String c : mngImplementationPreferences) {
      f = ApamFilter.newInstanceApam(c, linkSource);
      if (f != null) {
        allImplementationPreferenceFilters.add(f);
      }
    }

    for (String c : mngInstancePreferences) {
      f = ApamFilter.newInstanceApam(c, linkSource);
      if (f != null) {
        allInstancePreferenceFilters.add(f);
      }
    }

    /*
     * intrinsic constraints. To recompute only if they have substitutions.
     */
    reComputeSubstFilters();

  }

  /**
   * Recompute the filters if there are substitutions.
   * Supposed to be called each time an attribute is changes in the component (setProperty)
   */
  public void reComputeSubstFilters () {
    ApamFilter f;

    /*
     * intrinsic constraints. To recompute only if they have substitutions.
     */
    if (!getImplementationConstraints().isEmpty()) {
      if (!((RelationDefinitionImpl) relationDefinition).isStaticImplemConstraints()) {
        for (String c : relationDefinition.getImplementationConstraints()) {
          f = ApamFilter.newInstanceApam(c, linkSource);
          if (f != null) {
            allImplementationConstraintFilters.add(f);
          }
        }
      } else {
        allImplementationConstraintFilters.addAll(((RelationDefinitionImpl) relationDefinition).getImplementationConstraintFilters());
      }
    }

    if (!getInstanceConstraints().isEmpty()) {
      if (!((RelationDefinitionImpl) relationDefinition).isStaticInstConstraints()) {
        for (String c : relationDefinition.getInstanceConstraints()) {
          f = ApamFilter.newInstanceApam(c, linkSource);
          if (f != null) {
            allInstanceConstraintFilters.add(f);
          }
        }
      } else {
        allInstanceConstraintFilters.addAll(((RelationDefinitionImpl) relationDefinition).getInstanceConstraintFilters());
      }
    }

    if (!getImplementationPreferences().isEmpty()) {
      if (!((RelationDefinitionImpl) relationDefinition).isStaticImplemPreferences()) {
        for (String c : relationDefinition.getImplementationPreferences()) {
          f = ApamFilter.newInstanceApam(c, linkSource);
          if (f != null) {
            allImplementationPreferenceFilters.add(f);
          }
        }
      } else {
        allImplementationPreferenceFilters.addAll(((RelationDefinitionImpl) relationDefinition).getImplementationpreferencfeFilters());
      }
    }

    if (!getInstancePreferences().isEmpty()) {
      if (!((RelationDefinitionImpl) relationDefinition).isStaticInstPreferences()) {
        for (String c : relationDefinition.getInstancePreferences()) {
          f = ApamFilter.newInstanceApam(c, linkSource);
          if (f != null) {
            allInstancePreferenceFilters.add(f);
          }
        }
      } else {
        allInstancePreferenceFilters.addAll(((RelationDefinitionImpl) relationDefinition).getInstancePreferenceFilters());
      }
    }
  }
 
 
  // Supposed to be called after filters have been computed and added
  @Override
  public Set<ApamFilter> getAllImplementationConstraintFilters() {
    return Collections.unmodifiableSet(allImplementationConstraintFilters);
  }

  // Supposed to be called after filters have been computed and added
  @Override
  public Set<ApamFilter> getAllInstanceConstraintFilters() {
    return Collections.unmodifiableSet(allInstanceConstraintFilters);
  }

  @Override
  public CreationPolicy getCreation() {
    return relationDefinition.getCreation();
  }

  public RelationDeclaration getDeclaration() {
    return ((RelationDefinitionImpl) relationDefinition).getDeclaration();
  }

  /**
   * Get the constraints that need to be satisfied by the implementation that
   * resolves the reference
   */
  @Override
  public Set<String> getImplementationConstraints() {
    return relationDefinition.getImplementationConstraints();
  }

  @Override
  public List<ApamFilter> getImplementationPreferenceFilters() {
    return Collections.unmodifiableList(allImplementationPreferenceFilters);
  }

  // Get the resource provider preferences
  @Override
  public List<String> getImplementationPreferences() {
    return relationDefinition.getImplementationPreferences();
  }

  // Get the constraints that need to be satisfied by the instance that
  // resolves the reference
  @Override
  public Set<String> getInstanceConstraints() {
    return relationDefinition.getInstanceConstraints();
  }

  // Both list have been added after filter generation
  @Override
  public List<ApamFilter> getInstancePreferenceFilters() {
    return Collections.unmodifiableList(allInstancePreferenceFilters);
  }

  // Get the instance provider preferences
  @Override
  public List<String> getInstancePreferences() {
    return relationDefinition.getInstancePreferences();
  }

  @Override
  public Component getLinkSource() {
    return linkSource;
  }

  // Get the exception associated with the missing policy
  @Override
  public String getMissingException() {
    return relationDefinition.getMissingException();
  }

  // Get the policy associated with this relation
  @Override
  public MissingPolicy getMissingPolicy() {
    return relationDefinition.getMissingPolicy();
  }

  /*
   * Modifiable
   *
   * @see fr.imag.adele.apam.Relation#getMngImplementationConstraints()
   */
  @Override
  public Set<String> getMngImplementationConstraints() {
    return mngImplementationConstraints;
  }

  // Get the resource provider preferences
  @Override
  public List<String> getMngImplementationPreferences() {
    return mngImplementationPreferences;
  }

  // Get the constraints that need to be satisfied by the instance that
  // resolves the reference
  @Override
  public Set<String> getMngInstanceConstraints() {
    return mngInstanceConstraints;
  }

  // Get the instance provider preferences
  @Override
  public List<String> getMngInstancePreferences() {
    return mngInstancePreferences;
  }

  // Get the id of the relation in the declaring component declaration
  @Override
  public String getName() {
    return relationDefinition.getName();
  }

  /**
   * Return the candidates that best matches the preferences Take the
   * preferences in orden: m candidates find the n candidates that match the
   * constraint. if n= 0 ignore the constraint if n=1 return it. iterate with
   * the n candidates. At the end, if n > 1 returns the default one.
   *
   * @param <T>
   * @param candidates
   * @param preferences
   * @return
   */
  @Override
  public <T extends Component> T getPrefered(Set<T> candidates) {
    if (candidates == null || candidates.isEmpty()) {
      return null;
    }
    if (candidates.size() == 1) {
      return candidates.iterator().next();
    }

    if (candidates.iterator().next() instanceof Implementation) {
      return getPreferedFilter(candidates, getImplementationPreferenceFilters());
    }
    return getPreferedFilter(candidates, getInstancePreferenceFilters());
  }

  /**
   * Calculates the ranking of the given candidate according to the preferences.
   *
   */
  public int ranking(ComponentKind kind, Map<String, Object> candidate) {
    switch(kind) {
    case IMPLEMENTATION:
      return ranking(candidate,getImplementationPreferenceFilters());
    case INSTANCE:
      return ranking(candidate,getInstancePreferenceFilters());
    default:
      return 0;
   
    }
  }
 
  /**
   * Calculates the ranking of the given candidate according to the preferences.
   *
   * The ranking is the number of satisfied criteria of the candidate, in the
   * order of definition. If a criteria is not satisfied, the other preferences
   * are not considered.
   *
   * The higher the number the better the ranking.
   */
  private int ranking(Map<String, Object> candidate, List<ApamFilter> preferences) {

    if (!isInitialized) {
      computeFilters();
    }
   
    int ranking = 0;
    for (ApamFilter preference : preferences) {
      if (! preference.match(candidate))
        break;
     
      ranking++;
    }
   
    return ranking;

  }

  @Override
  public RelationDefinition getRelationDefinition() {
    return relationDefinition;
  }

  @Override
  public ResolvePolicy getResolve() {
    return relationDefinition.getResolve();
  }

  @Override
  public <T extends Component> Resolved<T> getResolved(Resolved<T> candidates, boolean isPromotion) {
    if (candidates.singletonResolved != null) {
      if (candidates.singletonResolved.matchRelationConstraints(this)) {
        return candidates;
      }
      else {
        return null;
      }
    }
    else {
      return getResolved(candidates.setResolved, isPromotion);
    }
  }

  // ==== ex RelationUtil
  /**
   * Return the sub-set of candidates that satisfy all the constraints and
   * preferences. Suppose the candidates are of the right kind ! Visibility is
   * checked is source is provided
   *
   */
  @Override
  public <T extends Component> Resolved<T> getResolved(Set<T> candidates, boolean isPromotion) {

    if (candidates == null || candidates.isEmpty()) {
      return null;
    }

    if (candidates.iterator().next().getKind() != getTargetKind()) {
      logger.error("Invalid type in getResolved");
      return null;
    }

    Set<T> matching = new HashSet<T>();
    for (T candidate : candidates) {
      if ((isPromotion || getLinkSource().canSee(candidate)) && candidate.matchRelationConstraints(this)) {
        matching.add(candidate);
      }
    }

    if (matching.isEmpty()) {
      return null;
    }

    if (isMultiple()) {
      return new Resolved<T>(matching);
    }

    // look for preferences
    return new Resolved<T>(getPrefered(matching));
  }

  @Override
  public ComponentKind getSourceKind() {
    return relationDefinition.getSourceKind();
  }

  /**
   * Get the reference to the required resource
   */
  @Override
  public ResolvableReference getTarget() {
    return relationDefinition.getTarget();
  }

  @Override
  public ComponentKind getTargetKind() {
    return relationDefinition.getTargetKind();
  }

  @Override
  public boolean hasConstraints() {
    return !allImplementationConstraintFilters.isEmpty() || !allInstanceConstraintFilters.isEmpty();
  }

  @Override
  public boolean hasPreferences() {
    return !allImplementationPreferenceFilters.isEmpty() || !allInstancePreferenceFilters.isEmpty();
  }

  @Override
  public boolean isDynamic() {
    return relationDefinition.isDynamic();
  }

  /**
   * Whether an error resolving a relation matching this policy should trigger
   * a backtrack in resolution
   */
  @Override
  public boolean isHide() {
    return relationDefinition.isHide();
  }

  @Override
  public boolean isInjected() {
    return relationDefinition.isInjected();
  }

  @Override
  public boolean isMultiple() {
    return relationDefinition.isMultiple();
  }

  @Override
  public boolean isRelation() {
    return !relationDefinition.getName().isEmpty();
  }

  @Override
  public boolean isWire() {
    return relationDefinition.isWire();
  }

  @Override
  public boolean matchRelation(Component target) {
    return (matchRelationConstraints(target) && matchRelationTarget(target));
  }

  /**
   * return true if the component matches the constraints of that relation.
   * Preferences are not taken into account
   *
   * @param comp
   * @return
   */
  @Override
  public boolean matchRelationConstraints(Component comp) {
    return matchRelationConstraints(comp.getKind(), comp.getAllProperties());
  }

  @Override
  public boolean matchRelationConstraints(ComponentKind candidateKind, Map<String, Object> properties) {

    if (!isInitialized) {
      computeFilters();
    }

    // Instance must match both implementation and instance constraints ???
    switch (candidateKind) {
    case INSTANCE:
      for (ApamFilter f : allInstanceConstraintFilters) {
        if (!f.match(properties)) {
          return false;
        }
      }
    case IMPLEMENTATION:
      for (ApamFilter f : allImplementationConstraintFilters) {
        if (!f.match(properties)) {
          return false;
        }
      }
    case SPECIFICATION:
    case COMPONENT:
    }

    return true;
  }

  @Override
  public boolean matchRelationTarget(Component target) {
    if (target.getKind() != getTargetKind()) {
      return false;
    }
    if (!linkSource.canSee(target)) {
      return false;
    }

    /*
     * target definition is a specification, an implementation or instance
     * by name
     */
    if (getTarget() instanceof ComponentReference<?>) {
      Component group = target;
      while (group != null) {
        if (group.getName().equals(getTarget().getName())) {
          return true;
        }
        group = group.getGroup();
      }
      return false;
    }

    // if (dep.getTarget() instanceof ResourceReference) {
    return target.getDeclaration().getProvidedResources().contains(getTarget());
  }


  @Override
  public String toString() {
    StringBuffer ret = new StringBuffer();
    // ret.append("resolving ");

    if (isRelation()) {
      ret.append("relation " + getName() + " towards ");
    }

    if (relationDefinition.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 = " + relationDefinition.getCreation() + ", resolve = " + relationDefinition.getResolve() + ", missing policy = " + relationDefinition.getMissingPolicy() + ")");

    if (!allImplementationConstraintFilters.isEmpty()) {
      ret.append("\n         Implementation Constraints");
      for (ApamFilter inj : allImplementationConstraintFilters) {
        ret.append("\n            " + inj);
        // if (!implementationConstraintFilters.contains(inj))
        // ret.append("[added by Manager]");
      }
    }
    if (!allInstanceConstraintFilters.isEmpty()) {
      ret.append("\n         Instance Constraints");
      for (ApamFilter inj : allInstanceConstraintFilters) {
        ret.append("\n            " + inj);
        // if (!instanceConstraintFilters.contains(inj))
        // ret.append("[added by Manager]");
      }
    }
    if (!allImplementationPreferenceFilters.isEmpty()) {
      ret.append("\n         Implementation Preferences");
      for (ApamFilter inj : allImplementationPreferenceFilters) {
        ret.append("\n            " + inj);
        // if (!implementationPreferenceFilters.contains(inj))
        // ret.append("[added by Manager]");
      }
    }
    if (!allInstancePreferenceFilters.isEmpty()) {
      ret.append("\n         Instance Preferences");
      for (ApamFilter inj : allInstancePreferenceFilters) {
        ret.append("\n            " + inj);
        // if (!instancePreferenceFilters.contains(inj))
        // ret.append("[added by Manager]");
      }
    }
    return ret.toString();
  }
}
TOP

Related Classes of fr.imag.adele.apam.impl.RelToResolveImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.