Package fr.imag.adele.apam.maven.plugin.validation

Source Code of fr.imag.adele.apam.maven.plugin.validation.RelationValidator

package fr.imag.adele.apam.maven.plugin.validation;

import fr.imag.adele.apam.CST;
import fr.imag.adele.apam.declarations.ComponentDeclaration;
import fr.imag.adele.apam.declarations.ComponentKind;
import fr.imag.adele.apam.declarations.RelationDeclaration;
import fr.imag.adele.apam.declarations.references.components.ComponentReference;
import fr.imag.adele.apam.declarations.references.resources.ResourceReference;
import fr.imag.adele.apam.declarations.references.resources.UnknownReference;

/**
* The common validation for relations defined in abstract components
*
* NOTE this class is intended to be sub-classed to specialize the verification
* in specific kinds of components
*
* @author vega
*
*/
public class RelationValidator extends ConstrainedReferenceValidator<RelationDeclaration> {

  public RelationValidator(ComponentValidator<?> parent) {
    super(parent);
  }

  public Void validate(RelationDeclaration relation) {
    super.validate(relation);
   
    validateRefinement();
    validateInstrumentation();
   
    return null;
  }

 
  @Override
  protected void validateTarget() {
   
    /*
     * For overrides the target may be a wildcard, so we skip validation
     */
    if (!getRelation().isOverride()) {
      super.validateTarget();
    }
   
    /*
     *  checking that the targetKind is not higher than the target
     */
    if (getTarget() != null && getTargetKind().isMoreAbstractThan(getTarget().getKind())) {
      error("Invalid relation " + quoted(getRelation().getIdentifier()) + " target kind "+quoted(getTargetKind().toString())+" is more abstract than the target "+getTarget().getName());
    }
   
  }

  @Override
  protected void validateConstraints() {
   
    super.validateConstraints();
   
    /*
     * check preferences according to cardinality
     */
    if (getRelation().isMultiple()) {
      if (!getRelation().getImplementationPreferences().isEmpty() || !getRelation().getInstancePreferences().isEmpty()) {
        error("invalid relation "+quoted(getRelation().getIdentifier())+ " preferences cannot be defined for multiple cardinality");
      }
    }
  }

  /**
   * Validates if a refinement of a relation defined in the group is allowed
   *
   */
  protected void validateRefinement() {


    if (CST.isFinalRelation(getRelation().getIdentifier())) {
      error("Invalid relation " + quoted(getRelation().getIdentifier()) + " is predefined and cannot be refined");
      return;
    }
   
    if (getGroupRelation() == null) {
      return;
    }

   
    boolean relationTargetDefined  = ! (getTargetReference() instanceof UnknownReference);
    boolean groupTargetDefined     = ! (getGroupRelation().getTarget() instanceof UnknownReference);

    if (!relationTargetDefined || !groupTargetDefined) {
      return;
    }

    /*
     * If the targets are defined at several levels they must be compatible
     */
   
     
    if (getGroupRelation().getTarget() instanceof ResourceReference) {
   
      /*
       * If the group targets a resource
       */
      ResourceReference groupTarget = getGroupRelation().getTarget().as(ResourceReference.class);
     
      /*
       * and the refinement targets a resource it must match
       */
      if (targetIsResource() && !getTargetReference().equals(groupTarget)) {
        error("Invalid target refinement in relation " + quoted(getRelation().getIdentifier()) + ", "+getTargetReference()+ " is not compatible with "+groupTarget);
      }
     
      /*
       * and the refinement targets a component, it must provide the resource
       */
      if (targetIsComponent() && getTarget() != null && !getTarget().getProvidedResources().contains(groupTarget)) {
        error("Invalid target refinement in relation " + quoted(getRelation().getIdentifier()) + ", "+getTargetReference()+ " doesn't provide the resource specified in the group "+groupTarget);
      }
    }
   
    if (getGroupRelation().getTarget() instanceof ComponentReference) {
     
      /*
       * If the group targets a component
       */
      ComponentDeclaration groupTarget = getComponent(getGroupRelation().getTarget().as(ComponentReference.class),true);

      /*
       * and the refinement targets a resource, it must be provided by the component
       */
      if (targetIsResource() && groupTarget != null && !groupTarget.getProvidedResources().contains(getTargetReference())) {
        error("Invalid target refinement in relation " + quoted(getRelation().getIdentifier()) + ", "+getTargetReference()+ " is not provided by the component specified in the group "+groupTarget.getName());
      }

      if (targetIsComponent() && getTarget() != null && groupTarget != null) {

        /*
         * and the refinement targets a most concrete component, it must be a descendant
         */

        if (groupTarget.getKind().isMoreAbstractThan(getTarget().getKind()) && ! isAncestor(getTarget(), groupTarget.getReference(),true)) {
          error("Invalid target refinement in relation " + quoted(getRelation().getIdentifier()) + ", "+getTargetReference()+ " is not a descendant of the component specified in the group "+groupTarget.getName());
        }
       
        /*
         * and the refinement targets a most abstract  component, it must be an ancestor
         */
        if (getTarget().getKind().isMoreAbstractThan(groupTarget.getKind()) && ! isAncestor(groupTarget,getTarget().getReference(),true)) {
          error("Invalid target refinement in relation " + quoted(getRelation().getIdentifier()) + ", "+getTargetReference()+ " is not a ancestor of the component specified in the group "+groupTarget.getName());
        }

        /*
         * and the refinement targets a equally abstract  component, it must be the samer
         */
        if (getTarget().getKind().equals(groupTarget.getKind()) && ! getTarget().equals(groupTarget)) {
          error("Invalid target refinement in relation " + quoted(getRelation().getIdentifier()) + ", "+getTargetReference()+ " is not compatible with the component specified in the group "+groupTarget.getName());
        }
       
      }
     
    }

  }

  /**
   * Validates if a instrumentation of a relation is valid
   *
   * In general, instrumentation is not allowed at all level of abstraction. This method must
   * be redefined in subclasses specialized for specific levels of abstraction that support it
   */
  protected void validateInstrumentation() {
   
    /*
     * validate callbacks
     */
    for (RelationDeclaration.Event event : RelationDeclaration.Event.values()) {
      if (getRelation().getCallback(event) != null) {
        error("Invalid relation " + quoted(getRelation().getIdentifier()) + ", cannot specify a "+event+" callback in an abstract component");
      }
    }

    /*
     * validate instrumented fields and methods
     */
    if (!getRelation().getInstrumentations().isEmpty()) {
      error("Invalid relation " + quoted(getRelation().getIdentifier()) + ", cannot specify field or method injection in an abstract component");
    }

    /*
     * validate missing exception
     */

    if (getRelation().getMissingException() != null) {
      checkResourceExists(new ResourceReference(getRelation().getMissingException()));
    }
   
  }


  /**
   * This is the group declaration that is refined by the relation being validated
   */
  private RelationDeclaration groupRelation;

  /**
   * This is the fully refined declaration corresponding to the relation being validated.
   *
   * NOTE Notice that when there are errors in the refinement this may give a wrong merge
   * that will lead to some false negatives during validation
   *
   */
  private RelationDeclaration effectiveRelation;
 
  @Override
  protected void initializeState(RelationDeclaration reference) {
    super.initializeState(reference);

    this.groupRelation     = getGroup() != null ? getGroup().getRelation(getRelation().getIdentifier()) : null;
    this.effectiveRelation  = getGroupRelation() != null ? getGroupRelation().refinedBy(getRelation()) : getRelation();
  }

  @Override
  public void resetState() {
    super.resetState();
    this.groupRelation     = null;
    this.effectiveRelation  = null;
  }


  /**
   * The declaration that is being validated
   */
  protected RelationDeclaration getRelation() {
    return super.getReference();
  }

  /**
   * The corresponding group declaration
   */
  protected RelationDeclaration getGroupRelation() {
    return groupRelation;
  }

  /**
   * The effective declaration after merging with group declaration
   */
  protected RelationDeclaration getEffectiveRelation() {
    return effectiveRelation;
  }

  /**
   * The effective target kind
   */
  protected ComponentKind getTargetKind() {
    ComponentKind effectiveTargetKind   = getEffectiveRelation().getTargetKind();
    return effectiveTargetKind != null ? effectiveTargetKind : ComponentKind.INSTANCE;
  }

}
 
TOP

Related Classes of fr.imag.adele.apam.maven.plugin.validation.RelationValidator

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.