Package fr.imag.adele.apam.impl

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

/**
* Copyright 2011-2012 Universite Joseph Fourier, LIG, ADELE team
*   Licensed under the Apache License, Version 2.0 (the "License");
*   you may not use this file except in compliance with the License.
*   You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
*   Unless required by applicable law or agreed to in writing, software
*   distributed under the License is distributed on an "AS IS" BASIS,
*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*   See the License for the specific language governing permissions and
*   limitations under the License.
*/
package fr.imag.adele.apam.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

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

import fr.imag.adele.apam.ApamManagers;
import fr.imag.adele.apam.ApamResolver;
import fr.imag.adele.apam.CST;
import fr.imag.adele.apam.Component;
import fr.imag.adele.apam.Composite;
import fr.imag.adele.apam.CompositeType;
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.RelationManager;
import fr.imag.adele.apam.Resolved;
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.ImplementationDeclaration;
import fr.imag.adele.apam.declarations.RelationPromotion;
import fr.imag.adele.apam.declarations.ResolvePolicy;
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.InstanceReference;
import fr.imag.adele.apam.declarations.references.components.SpecificationReference;
import fr.imag.adele.apam.declarations.references.resources.InterfaceReference;
import fr.imag.adele.apam.declarations.references.resources.MessageReference;

public class ApamResolverImpl implements ApamResolver {


  private APAMImpl apam;

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

  /**
   * The current state of the resolver. The resolver can be temporarily
   * disabled, for instance for waiting for the installation of required
   * managers;
   *
   */
  private boolean enabled = false;

  /**
   * A description of the condition that must be met to enable the resolver
   * again.
   */
  private String condition = "resolver startup";

  /**
   * If the resolver is disabled, the time at which it will be automatically
   * enabled, even if the condition is not met. This is not an delay, but the
   * actual future time.
   */
  private long maxDisableTime = 0L;

  public ApamResolverImpl(APAMImpl theApam) {
    this.apam = theApam;
  }
 
  /**
   * Impl is either unused or deployed (and therefore also unused). It becomes
   * embedded in compoType. If unused, remove from unused list.
   *
   * @param compoType
   * @param impl
   */
  private static void deployedImpl(Component source, Component comp, boolean deployed) {
    // We take care only of implementations
    if (!(comp instanceof Implementation)) {
      return;
    }

    Implementation impl = (Implementation) comp;
    // it was not deployed
    if (!deployed && impl.isUsed()) {
      logger.info(" : selected " + impl);
      return;
    }

    CompositeType compoType;
    if (source instanceof Instance) {
      compoType = ((Instance) source).getComposite().getCompType();
    } else if (source instanceof Implementation) {
      compoType = ((Implementation) source).getInCompositeType().iterator().next();
    } else {
      logger.error("Should not call deployedImpl on a source Specification " + source);
      // TODO in which composite to put it. Still in root ?
      return;
    }
    ((CompositeTypeImpl) compoType).deploy(impl);

    // it is deployed or was never used so far
    if (impl.isUsed()) {
      logger.info(" : logically deployed " + impl);
    } else {// it was unused so far.
      ((ComponentImpl) impl).setFirstDeployed(compoType);
      if (deployed) {
        logger.info(" : deployed " + impl);
      } else {
        logger.info(" : was here, unused " + impl);
      }
    }
  }


  /**
   * Verifies if the resolver is enabled. If it is disabled blocks the calling
   * thread waiting for the enable condition.
   */
  private synchronized void checkEnabled() {
    while (!this.enabled) {
      try {

        /*
         * Verify if the disable timeout has expired, in that case
         * simply enable the resolver again.
         */
        long currentTime = System.currentTimeMillis();
        if (currentTime > maxDisableTime) {

          logger.debug("APAM RESOLVER resuming resolution, condition did not happen: " + condition);
          enable();
          return;
        }

        logger.debug("APAM RESOLVER waiting for: " + condition);
        wait(this.maxDisableTime - currentTime);

      } catch (InterruptedException ignored) {
      }
    }
  }

  /**
   * Disables the resolver until the specified condition is met. If the
   * condition is not signaled before the specified timeout, the resolver will
   * be automatically enabled.
   */
  public synchronized void disable(String condition, long timeout) {
   
    logger.debug("Resolver disabled waiting for "+condition);
    this.enabled = false;
    this.condition = condition;
    this.maxDisableTime = System.currentTimeMillis() + timeout;

  }

  /**
   * Enables the resolver after the condition is met
   */
  public synchronized void enable() {

    logger.debug("Resolver enabled");

    this.enabled = true;
    this.condition = null;
    this.maxDisableTime = 0L;

    this.notifyAll();
  }

  private Component findByName(Component client, ComponentReference<?> targetComponent, ComponentKind targetKind) {
    if (client == null) {
      client = CompositeImpl.getRootInstance();
      // hummmm patch .... TODO
      if (targetComponent.getName().equals(CST.ROOT_COMPOSITE_TYPE)) {
        return CompositeTypeImpl.getRootCompositeType();
      }
    }

    // CompositeType compoType = CompositeTypeImpl.getRootCompositeType();

    RelationDefinition rel = new RelationDefinitionImpl(targetComponent, client.getKind(), targetKind, null, null);
    Resolved<?> res = resolveLink(client, rel);
    if (res == null) {
      return null;
    }
    return res.singletonResolved;
  }

  @Override
  public Component findComponentByName(Component client, String name) {
    Component ret = findImplByName(client, name);
    if (ret != null) {
      return ret;
    }
    ret = findSpecByName(client, name);
    if (ret != null) {
      return ret;
    }
    return findInstByName(client, name);
  }

  @Override
  public Implementation findImplByName(Component client, String implName) {
    return (Implementation) findByName(client, new ImplementationReference<ImplementationDeclaration>(implName), ComponentKind.IMPLEMENTATION);
  }

  @Override
  public Instance findInstByName(Component client, String instName) {
    return (Instance) findByName(client, new InstanceReference(instName), ComponentKind.INSTANCE);
  }


  @Override
  public Specification findSpecByName(Component client, String specName) {
    return (Specification) findByName(client, new SpecificationReference(specName), ComponentKind.SPECIFICATION);
  }

  /**
   * Get the subset of the links of a composite that can satisfy a promotion for the specified source and relation
   * inside the composite.
   *
   * NOTE IMPORTANT this method may trigger resolution of the composite's relation
   */
  @SuppressWarnings("unchecked")
  private <T extends Component> Resolved<T> getPromotionCandidates(Instance source, RelToResolve relation, RelationDefinition compositeRelation) {

    Set<Component> candidates = source.getComposite().getLinkDests(compositeRelation.getName());
   
    /*
     * It there is no candidates, force resolution of the composite's relation
     */
    if (candidates.isEmpty()) {
      resolveLink(source.getComposite(), compositeRelation);
      candidates = source.getComposite().getLinkDests(compositeRelation.getName());
    }
   
    /*
     * Select the candidates that match the relation constraints
     */
    return (Resolved<T>) relation.getResolved(candidates,true);
  }

  /**
   * Look if a promotion is explicitly declared for the specified client and relation, and returns the result
   * of promoting the relation
   *
   */
  private <T extends Component> Resolved<T> checkExplicitPromotion(Instance client, RelToResolve relation) {
   
    Resolved<T> promotionResult  = null;
   
    search:
    for (RelationPromotion promotion : client.getComposite().getCompType().getCompoDeclaration().getPromotions()) {
     
      /*
       * check if the relation to resolve matches the identifier of the promoted relation
       */
      if (!promotion.getContentRelation().getIdentifier().equals(relation.getName())) {
        continue;
      }

      /*
       * check if the source of the promoted relation matches the client (or one of its ancestor groups)
       */
      String source     = promotion.getContentRelation().getDeclaringComponent().getName();
      Component matching   = null;
      Component ancestor  = client;
     
      while (matching == null && ancestor != null) {
        if (ancestor.getName().equals(source)) {
          matching = ancestor;
        }
       
        ancestor = ancestor.getGroup();
      }
     
      /*
       * If we find a matching explicit promotion try to resolve using the matched composite relation
       */
      if (matching != null) {
       
        RelationDefinition compositeRelation  = client.getComposite().getRelation(promotion.getCompositeRelation().getIdentifier());
       
        /*
         * Validate the source's and composite's relations are compatible.
         *
         * NOTE This is already validated at build time, but we do the tests again at runtime
         */
        if (!relation.getRelationDefinition().matchRelation(client,compositeRelation)) {
          logger.error("Promotion is invalid. relation " + relation.getName() + " of component " + client.getName() + " does not match the composite relation " + compositeRelation);
          continue search;
        }
         
        Resolved<T> candidates = getPromotionCandidates(client, relation, compositeRelation);
        if (candidates != null && !candidates.isEmpty()) {

          /*
           * Create the promotion links and return
           */
          updateModel(client, relation, candidates, relation.hasConstraints() || compositeRelation.hasConstraints(), true);
         
          /*
           * NOTE IMPORTAN SPECIAL CASE for relations with cardinality multiple, we allow merging the result of
           * several promotions
           */
          if (relation.isMultiple()) {
            promotionResult = candidates.merge(promotionResult);
            continue search;
          }
          else {
            promotionResult = candidates;
            break search;
          }

        }
      }
    }
   
   
    return promotionResult;
  }

  /**
   * Look if a relation defined in the composite matches implicitly the specified relation, and tries to perform
   * an implicit promotion
   */
  private <T extends Component> Resolved<T> checkImplicitPromotion(Instance client, RelToResolve relation) {

    Resolved<T> promotionResult  = null;

    search:
    for (RelationDefinition compositeRelation : client.getComposite().getRelations()) {

      if (!relation.getRelationDefinition().matchRelation(client,compositeRelation)) {
        continue search;
      }
     
      Resolved<T> candidates = getPromotionCandidates(client, relation, compositeRelation);
      if (candidates != null && !candidates.isEmpty()) {

        /*
         * Create the promotion links and return
         */
        updateModel(client, relation, candidates, relation.hasConstraints() || compositeRelation.hasConstraints(), true);
       
        /*
         * NOTE IMPORTAN SPECIAL CASE for relations with cardinality multiple, we allow merging the result of
         * several promotions
         */
        if (relation.isMultiple()) {
          promotionResult = candidates.merge(promotionResult);
          continue search;
        }
        else {
          promotionResult = candidates;
          break search;
        }

      }
    }
    return promotionResult;
  }



  /**
   * Performs a complete resolution of the relation, or resolution.
   *
   * The managers is asked to find the "right" component.
   *
   * @param client
   *            the instance calling implem (and where to create
   *            implementation ans instances if needed). Cannot be null.
   * @param relToResolve
   *            a relation declaration containing the type and name of the
   *            relation target. It can be -the specification Name (new
   *            SpecificationReference (specName)) -an implementation name
   *            (new ImplementationRefernece (name) -an interface name (new
   *            InterfaceReference (interfaceName)) -a message name (new
   *            MessageReference (dataTypeName))
   * @return the component(s) if resolved, null otherwise
   */
  private <T extends Component> Resolved<T> resolveByManagers(RelToResolve relToResolve) {

    /*
     * Get the list of external managers.
     *
     * NOTE that we invoke getSelectionPath on all managers (even if
     * resolve policy is specified EXTERNAL). In this way, managers can
     * influence resolution, by adding constraints, even if they do not
     * perform resolution themselves.
     *
     */

    SortedSet<RelationManager> externalManagers = new TreeSet<RelationManager>(ApamManagers.getRelationManagers().comparator());
   
    for (RelationManager relationManager : ApamManagers.getRelationManagers()) {
      if (relationManager.beginResolving(relToResolve))
        externalManagers.add(relationManager);
    }
    // Compute filters once for all, and make it final
    ((RelToResolveImpl) relToResolve).computeFilters();

    /*
     * Get the list of all managers
     */
    List<RelationManager> selectionPath = new ArrayList<RelationManager>();

    selectionPath.add(0, apam.getApamMan());
    selectionPath.add(0, apam.getUpdateMan());
    if (apam.getApamMan() == null) {
      throw new RuntimeException("Error while get of ApamMan");
    }
    if (apam.getUpdateMan() == null) {
      throw new RuntimeException("Error while get of UpdateMan");
    }

    /*
     * If resolve = exist or internal, only predefined managers must be called
     */
    boolean resolveExternal = (relToResolve.getResolve() == ResolvePolicy.EXTERNAL);
    if (resolveExternal) {
      selectionPath.addAll(externalManagers);
    }

    if (!relToResolve.isRelation()) { // It is a find
      logger.info("Looking for " + relToResolve.getTargetKind() + " " + relToResolve.getTarget().getName());
    } else {
      logger.info("Resolving " + relToResolve);
    }

    Resolved<T> res ;
    String mess = "";

    for (RelationManager manager : selectionPath) {
      if (manager == null) {
        throw new RuntimeException("Manager is null, SelectionPath " ) ; //+ selectionPath);
      }
      if (manager.getName() == null) {
        throw new RuntimeException("Manager : " + manager + ", manager name is null");
      }     
      mess += manager.getName() + "  ";
            logger.debug("Calling manager "+manager.getName());

      res = resolveOneManager(manager, relToResolve, mess) ;
      if (res != null)
        return res ;
    }
   
    //All managers have been tried. No solution found
    logger.debug(mess + " : not found");
    return null;
  }


  @SuppressWarnings("unchecked")
  private <T extends Component> Resolved<T> resolveOneManager (RelationManager manager, RelToResolve relToResolve, String mess) {

    Resolved<T> resolved = (Resolved<T>) manager.resolve(relToResolve);
   
        logger.debug("resolveOneManager(...), manager resolve returns "+(resolved==null?null:resolved.toString()));
    if (resolved == null || resolved.isEmpty()) {
      return null;
    }

    /*
     * This manager succeeded to find a solution If an unused or deployed
     * implementation. Can be into singleton or in toInstantiate if an
     * instance is required
     */
    Component source = relToResolve.getLinkSource();
    boolean deployed = !manager.getName().equals(CST.APAMMAN) && !manager.getName().equals(CST.UPDATEMAN) ;
    Component depl = (resolved.toInstantiate != null) ? resolved.toInstantiate : resolved.singletonResolved;

    deployedImpl(source, depl, deployed);

    /*
     * If an implementation is returned as "toInstantiate" it has to be instantiated
     */
    if (resolved.toInstantiate != null) {
      if (relToResolve.getTargetKind() != ComponentKind.INSTANCE) {
        logger.error(mess + "Invalid Resolved value. toInstantiate is set, but target kind is not an Instance");
        return null;
      }

      /*
       * If resolveExist, we cannot instantiate.
       */
      if (relToResolve.getResolve() == ResolvePolicy.EXIST) {
        logger.error(mess + "resolve=\"exist\" but no valid instance of " + resolved.toInstantiate + " are found. Resolve failed.");
        return null;
      }

      /*
       * This external manager returned a non instantiable implem (ApamMan does not do that).
       * Try this manager again but with a constraint avoiding to find the same implem.
       */
      if (!resolved.toInstantiate.isInstantiable()) {
        logger.debug(mess + "Implementation non-instantiable " + resolved.toInstantiate + " was found, but no valid instance. Resolve failed.");
        relToResolve.getMngImplementationConstraints().add("(!(name = " + resolved.toInstantiate.getName() + "))") ;
        ((RelToResolveImpl)relToResolve).computeFilters();
        return resolveOneManager(manager, relToResolve, mess);
      }

      Composite compo = (source instanceof Instance) ? ((Instance) source).getComposite() : CompositeImpl.getRootInstance();
      Instance inst = resolved.toInstantiate.createInstance(compo, null);
      if (inst == null) {
        /*
         *  Failed to be instantiated.
         *  Flag instantiateFails is turned to "true" in createInstance.
         *  Instantiation will not be attempted again on this implem.
         */
        logger.error(mess + "Failed creating instance. " + resolved.toInstantiate + " turned to non-instantiable.");
        //try to resolve again from beginning but prohibits this implementation (for external managers like OBRMan)
        relToResolve.getMngImplementationConstraints().add("(!(name = " + resolved.toInstantiate.getName() + "))") ;
        ((RelToResolveImpl)relToResolve).computeFilters();
        return resolveOneManager(manager, relToResolve, mess);
      }

      if (!relToResolve.matchRelationConstraints(inst)) {
        logger.debug(mess + " Instantiated instance " + inst + " does not match the constraints");
        ((ComponentBrokerImpl)CST.componentBroker).disappearedComponent(inst);
        return null ;
      }

      logger.info(mess + "Instantiated " + inst);
      if (relToResolve.isMultiple()) {
        Set<Instance> insts = new HashSet<Instance>();
        insts.add(inst);
        return (Resolved<T>) new Resolved<Instance>(insts);
      } else {
        return (Resolved<T>) new Resolved<Instance>(inst);
      }
    } //end instantiating 

    /*
     * We have the solution, including the instance if an instance is required.
     * But because managers can be third party, we cannot trust them.
     * We have to check if the result is correct.
     */
    if (relToResolve.isMultiple()) {
      if (resolved.setResolved == null || resolved.setResolved.isEmpty()) {
        logger.info(mess + "manager " + manager + " returned an empty result. Should be null.");
        return null ;
      }
      if (((Component) resolved.setResolved.iterator().next()).getKind() != relToResolve.getTargetKind()) {
        logger.error(mess + "Manager " + manager + " returned objects of the bad type for relation " + relToResolve);
        return null ;
      }
      logger.info(mess + "Selected : " + resolved.setResolved);
      return resolved;
    }

    // Result is a singleton
    if (resolved.singletonResolved == null) {
      logger.info(mess + "manager " + manager + " returned an empty result. ");
      return null ;
    }
    if (resolved.singletonResolved.getKind() != relToResolve.getTargetKind()) {
      logger.error(mess + "Manager " + manager + " returned objects of the bad type for relation " + relToResolve);
      return null ;
    }
    logger.info(mess + "Selected : " + resolved.singletonResolved);
    return resolved;
  }
 
 
  @Override
  public Instance resolveImpl(Component client, Implementation impl, Set<String> constraints, List<String> preferences) {
    if (client == null) {
      client = CompositeImpl.getRootInstance();
    }

    @SuppressWarnings("rawtypes")
    // RelToResolve dep = new RelToResolveImpl(new
    // ImplementationReference(impl.getName()), client.getKind(),
    // ComponentKind.INSTANCE, constraints, preferences);
    RelationDefinition dep = new RelationDefinitionImpl(new ImplementationReference(impl.getName()), client.getKind(), ComponentKind.INSTANCE, constraints, preferences);

    Resolved<?> resolve = resolveLink(client, dep);
    if (resolve == null) {
      return null;
    }
    return (Instance) resolve.setResolved;
  }

  @SuppressWarnings("unchecked")
  @Override
  public Set<Instance> resolveImpls(Component client, Implementation impl, Set<String> constraints) {
    if (client == null) {
      client = CompositeImpl.getRootInstance();
    }

    @SuppressWarnings("rawtypes")
    // RelToResolve dep = new RelToResolveImpl(new
    // ImplementationReference(impl.getName()), client.getKind(),
    // ComponentKind.INSTANCE, constraints, null);
    RelationDefinition dep = new RelationDefinitionImpl(new ImplementationReference(impl.getName()), client.getKind(), ComponentKind.INSTANCE, constraints, null);

    Resolved<?> resolve = resolveLink(client, dep);
    if (resolve == null) {
      return null;
    }
    return (Set<Instance>) resolve.setResolved;
  }

  /**
   * The central method for the resolver.
   */
  @Override
  public Resolved<?> resolveLink(Component source2, RelationDefinition rel) {

    /*
     * verify the resolver is actually ready to work (all managers are
     * present)
     */
    checkEnabled();

    if (source2 == null || rel == null) {
      logger.error("missing client or relation ");
      return null;
    }

    /*
     * If manual, the resolution must fail silently
     */
    boolean createManual = rel.getCreation() == CreationPolicy.MANUAL;
    if (createManual) {
      return null;
    }

    Component source = rel.getRelSource(source2);
    if (source == null) {
      logger.error("Component source not at the right level; found " + source2 + " expected " + rel.getSourceKind());
      return null;
    }


    /*
     *  Creates an relToResolve only considering the relation. Not completely initialized.
     */
    RelToResolve relToResolve  = new RelToResolveImpl(source, rel);
    Resolved<Component> resolved     = null;

    /*
     * If the source is an instance, verify if there is explicit promotions declared in the composite
     *
     *  TODO When an explicit promotion is declared, we perform resolution inside the composite if the
     *  promotion fails. This is not very intuitive but is more resilient, to discuss which is the good
     *  specification.
     */
    if (source instanceof Instance) {
      resolved = checkExplicitPromotion((Instance) source, relToResolve);
    }

    /*
     * If the source is not an instance or there is no explicit promotion, delegate to managers
     */
    if (resolved == null) {

      /*
       * Delegate resolution to managers and update the model
       */
      resolved = this.resolveByManagers(relToResolve);
      if (resolved != null) {
        updateModel(source, relToResolve, resolved, relToResolve.hasConstraints(),false);
      }
     
      /*
       * As a last resort try implicit promotion
       *
       * NOTE Notice that we recreate the relation to resolve from the declarations, to be sure
       * that we ignore all constraints that could be added by the managers during the first try
       */
      if (resolved == null && source instanceof Instance) {
        resolved = checkImplicitPromotion((Instance) source,new RelToResolveImpl(source,rel));
      }
      else if (resolved != null && source instanceof Instance && relToResolve.isMultiple()) {
        /*
         * TODO For relations with cardinality multiple, we try to merge all available targets,
         * so we merge the managers' result with the implicit promotions. This is not very intuitive
         * but is more resilient, to discuss which is the good specification.
         */
        resolved = resolved.merge(checkImplicitPromotion((Instance) source, relToResolve));
      }
    }

    return handleFailure(relToResolve,resolved);
  }


  /**
   * Updates the model to create all the links corresponding to the resolution result
   */
  private void updateModel(Component source, RelToResolve relation, Resolved<?> resolutionResult, boolean hasConstraints, boolean isPromotion) {
   
    if (resolutionResult == null || resolutionResult.isEmpty()) {
      return;
    }
   
    if (resolutionResult.singletonResolved != null) {
      source.createLink(resolutionResult.singletonResolved, relation, hasConstraints, isPromotion);
    }
    else {
      for (Component target : resolutionResult.setResolved) {
        source.createLink(target, relation, hasConstraints, isPromotion);
      }
    }
  }

  private Resolved<?> handleFailure(RelToResolve relToResolve, Resolved<?> result) {
    /*
     * If managers could not resolve and relation cannot be promoted, give a
     * chance to failure manager
     */
    if (result == null || result.isEmpty()) {
      result = apam.getFailedResolutionManager().resolve(relToResolve);
    }

    /*
     * If failure manager could not recover, just give up
     */
    if (result == null || result.isEmpty()) {
      if (relToResolve.getRelationDefinition().getName().isEmpty())
        logger.error("Failed to resolve " + relToResolve.getRelationDefinition().getTarget().getName() + " from " + relToResolve.getLinkSource() );
      else
        logger.error("Failed to resolve " + relToResolve.getRelationDefinition().getTarget().getName() + " from " + relToResolve.getLinkSource() + "(relation " + relToResolve.getRelationDefinition().getName() + ")");
      return null;
    }

    return result;
  }

  /**
   * An APAM client instance requires to be wired with one or all the
   * instances that satisfy the relation. WARNING : in case of interface or
   * message relation , since more than one specification can implement the
   * same interface, any specification implementing at least the provided
   * interface (technical name of the interface) will be considered
   * satisfactory. If found, the instance(s) are bound is returned.
   *
   * @param source
   *            the instance that requires the specification
   * @param depName
   *            the relation name. Field for atomic; spec name for complex
   *            dep, type for composite.
   * @return
   */

  @Override
  public Resolved<?> resolveLink(Component source, String depName) {
    if ((depName == null) || (source == null)) {
      logger.error("missing client or relation name");
      return null;
    }

    // Get the relation
    RelationDefinition relDef = source.getRelation(depName);
    if (relDef == null) {
      logger.error("Relation declaration invalid or not found " + depName);
      return null;
    }
    return resolveLink(source, relDef);
  }

  @Override
  public Implementation resolveSpecByInterface(Component client, String interfaceName, Set<String> constraints, List<String> preferences) {

    RelationDefinition dep = new RelationDefinitionImpl(new InterfaceReference(interfaceName), client.getKind(), ComponentKind.IMPLEMENTATION, constraints, preferences);
    return resolveSpecByResource(client, dep);
  }

  @Override
  public Implementation resolveSpecByMessage(Component client, String messageName, Set<String> constraints, List<String> preferences) {

    RelationDefinition dep = new RelationDefinitionImpl(new MessageReference(messageName), client.getKind(), ComponentKind.IMPLEMENTATION, constraints, preferences);
    return resolveSpecByResource(client, dep);
  }

  /**
   * First looks for the specification defined by its name, and then resolve
   * that specification. Returns the implementation that implement the
   * specification and that satisfies the constraints.
   *
   * @param compoType
   *            : the implementation to return must either be visible from
   *            compoType, or be deployed.
   * @param specName
   * @param constraints
   *            . The constraints to satisfy. They must be all satisfied.
   * @param preferences
   *            . If more than one implementation satisfies the constraints,
   *            returns the one that satisfies the maximum number of
   *            preferences, taken in the order, and stopping at the first
   *            failure.
   * @return
   */
  @Override
  public Implementation resolveSpecByName(Instance client, String specName, Set<String> constraints, List<String> preferences) {
    if (client == null) {
      client = CompositeImpl.getRootInstance();
    }

    RelationDefinition dep = new RelationDefinitionImpl(new SpecificationReference(specName), client.getKind(), ComponentKind.IMPLEMENTATION, constraints, preferences);

    return resolveSpecByResource(client, dep);
  }

  /**
   * First looks for the specification defined by its interface, and then
   * resolve that specification. Returns the implementation that implement the
   * specification and that satisfies the constraints.
   *
   * @param compoType
   *            : the implementation to return must either be visible from
   *            compoType, or be deployed.
   * @param interfaceName
   *            . The full name of one of the interfaces of the specification.
   *            WARNING : different specifications may share the same
   *            interface.
   * @param interfaces
   *            . The complete list of interface of the specification. At most
   *            one specification can be selected.
   * @param constraints
   *            . The constraints to satisfy. They must be all satisfied.
   * @param preferences
   *            . If more than one implementation satisfies the constraints,
   *            returns the one that satisfies the maximum number of
   *            preferences, taken in the order, and stopping at the first
   *            failure.
   * @return
   */
  public Implementation resolveSpecByResource(Component client, RelationDefinition relDef) {
    if (relDef.getTargetKind() != ComponentKind.IMPLEMENTATION) {
      logger.error("Invalid target type for resolveSpecByResource. Implemntation expected, found : " + relDef.getTargetKind());
      return null;
    }
    Resolved<?> resolve = resolveLink(client, relDef);
    if (resolve == null) {
      return null;
    }

    if (resolve.singletonResolved != null) {
      return (Implementation) resolve.singletonResolved;
    }
    return (Implementation) resolve.setResolved.iterator().next();
  }

  @Override
  public void updateComponent(String componentName) {
    Implementation impl = CST.componentBroker.getImpl(componentName);
    if (impl == null) {
      logger.error("Unknown component " + componentName);
      return;
    }
    UpdateMan.updateComponent(impl);
  }

}
TOP

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

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.