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

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

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

import java.util.HashSet;
import java.util.Set;

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.CompositeDeclaration;
import fr.imag.adele.apam.declarations.GrantDeclaration;
import fr.imag.adele.apam.declarations.InstanceDeclaration;
import fr.imag.adele.apam.declarations.OwnedComponentDeclaration;
import fr.imag.adele.apam.declarations.PropertyDefinition;
import fr.imag.adele.apam.declarations.RelationDeclaration;
import fr.imag.adele.apam.declarations.RelationPromotion;
import fr.imag.adele.apam.declarations.SpecificationDeclaration;
import fr.imag.adele.apam.declarations.VisibilityDeclaration;
import fr.imag.adele.apam.declarations.references.components.ComponentReference;
import fr.imag.adele.apam.declarations.references.resources.InterfaceReference;
import fr.imag.adele.apam.declarations.references.resources.MessageReference;
import fr.imag.adele.apam.declarations.references.resources.ResourceReference;
import fr.imag.adele.apam.declarations.repository.maven.Classpath;
import fr.imag.adele.apam.maven.plugin.validation.property.EnumerationType;
import fr.imag.adele.apam.maven.plugin.validation.property.Type;
import fr.imag.adele.apam.maven.plugin.validation.property.TypeParser;
import fr.imag.adele.apam.util.ApamFilter;
import fr.imag.adele.apam.util.Util;

public class CompositeValidator extends ComponentValidator<CompositeDeclaration> {

  /**
   * The parser used to validate all defined property types
   */
  private final TypeParser   typeParser;
 
  /**
   * The start instance validator
   */
  private final InstanceValidator instanceValidator;
 
  /**
   * The contextual dependencies validator
   */
  private final RelationValidator contextuallRelationValidator;
 
  public CompositeValidator(ValidationContext context, Classpath classpath) {
    super(context, classpath);
   
    this.typeParser            = new TypeParser();
    this.instanceValidator        = new InstanceValidator(this);
    this.contextuallRelationValidator  = new RelationValidator(this);
  }

  /**
   * Parses the specified type
   */
  protected Type getType(PropertyDefinition property) {
    return typeParser.parse(property.getType());
  }
 
  @Override
  public Void validate(CompositeDeclaration component) {
    Void result = super.validate(component);
   
    validateMain();
    validateContent();
   
    return result;
  }
 
  /**
   * Validates the main implementation
   */
  private void validateMain() {
   
    /*
     *  Abstract composites have no main component, but must not provide any resource
     */
    if (getComposite().getMainComponent() == null) {
      if (! getComposite().getProvidedResources(ResourceReference.class).isEmpty()) {
        error(" abstract composites can not provide resources");
      }
      return;
    }

    /*
     *  Concrete composites must have a main component that provides everything provided by the composite
     */
    ComponentDeclaration main   = getComponent(getComposite().getMainComponent(),true);
    if (main == null) {
      error(" main component "+getComposite().getMainComponent().getName()+" could not be found");
      return;
    }
   
    if (getComposite().getGroupVersioned() != null && main.getGroupVersioned() != null && !getComposite().getGroupVersioned().equals(main.getGroupVersioned()) ) {
      error("main component "+ main.getName() + " must implement specification " + getComposite().getGroupVersioned().getName());
    }

    validateMainProvides(main,InterfaceReference.class);
    validateMainProvides(main,MessageReference.class);
  }

  /**
   * Validates the provided resources of the main implementation
   */
  private void validateMainProvides(ComponentDeclaration main, Class<? extends ResourceReference> kind) {
    Set<? extends ResourceReference> compositeResources  = getComposite().getProvidedResources(kind);
    Set<? extends ResourceReference> mainResources     = main.getProvidedResources(kind);

    if (!mainResources.containsAll(compositeResources)) {
      error("invalid main implementation, "+ main.getName() + " must provide " + Util.list(compositeResources,true));
    }
  }

  /**
   * check all the characteristics that can be found in the content management declaration
   *
   */
  private void validateContent() {

    validateVisibility();
    validateOwn();
    validatePromotions();

    validateStart();
    validateContextualRelations();
  }


  private void validateVisibility() {
   
    VisibilityDeclaration visibility = getComposite().getVisibility();
   
    validateVisibilityExpression(visibility.getApplicationInstances(), "bad expression in ExportApp visibility");
    validateVisibilityExpression(visibility.getExportImplementations(),"bad expression in Export implementation visibility");
    validateVisibilityExpression(visibility.getExportInstances(),"bad expression in Export instance visibility");
    validateVisibilityExpression(visibility.getImportImplementations(),"bad expression in Imports implementation visibility");
    validateVisibilityExpression(visibility.getImportInstances(),"bad expression in Imports instance visibility");
  }
 
  private void validateVisibilityExpression(String expression, String message) {

    if (expression == null || expression.equals(CST.V_FALSE) || expression.equals(CST.V_TRUE)) {
      return;
    }

    ApamFilter parsedExpression = parseFilter(expression);
    if (parsedExpression == null) {
      error(message+" "+quoted(expression));
    }

  }
 
  /**
   * Validate own declarations
   */
  private void validateOwn() {

    /*
     * A state may optionally be defined to allow grant specification
     */
    Type stateType = validateState();
   
    /*
     *  The composite must be a singleton to define owns
     */
    if (!getComposite().getOwnedComponents().isEmpty() && !getComposite().isSingleton()) {
      error("invalid own expression, a composite must be a singleton to define "+quoted("own")+" clauses");
    }


    /*
     *  Check that a single own clause is defined for a component and its members
     */
    Set<ComponentReference<?>> ownedComponents = new HashSet<ComponentReference<?>>();
   
    for (OwnedComponentDeclaration ownDeclaration : getComposite().getOwnedComponents()) {
     
      ComponentDeclaration owned = getComponent(ownDeclaration.getComponent(),true);
      if (owned == null) {
        error("invalid own expression, unknown component " + ownDeclaration.getComponent().getName());
        continue;
      }


      /*
       * Verify the property used to optionally filter owned components is declared, and is an enumeration
       * that contains the specified values
       */
      if (ownDeclaration.getProperty() != null) {

        String propertyName      = ownDeclaration.getProperty().getIdentifier();
        PropertyDefinition property = owned.getPropertyDefinition(propertyName);
       
        if (property == null) {
          error("invalid own expression, undefined property "+ quoted(propertyName) +" in component "+ owned.getName());
          continue;
        }
       
        Type propertyType = getType(property);
        if (propertyType == null || !(propertyType instanceof EnumerationType)) {
          error("invalid own expression, property "+ quoted(propertyName) + " of component " + owned.getName() + " is not an enumeration");
          continue;
        }

        if (ownDeclaration.getValues().isEmpty()) {
          error("invalid own expression, values not specified for property "+ quoted(propertyName) + " of component " + owned.getName());
          continue;
        }

        for (String value : ownDeclaration.getValues()) {
          if (propertyType.value(value) == null) {
            error("invalid own expression, value "+quoted(value)+" is not valid for property "+ quoted(propertyName) + " of component " + owned.getName());
          }
        }
      }

      /*
       * Check that a single own clause applies for the same component and its members. At execution, it must also
       * be checked that if there are other grant clauses in other composites for the same component, they must
       * specify the same property and different values.
       */
      if (ownedComponents.contains(owned.getReference())) {
        error("invalid own expression, another own  clause exists for "+ owned.getName()+ " in this composite declaration");
        continue;
      }
     
      ownedComponents.add(owned.getReference());
      if (owned.getGroup() != null) {
        ownedComponents.add(owned.getGroup());
      }

      validateGrant(owned,ownDeclaration,stateType);
    }
  }

  private void validateGrant(ComponentDeclaration owned, OwnedComponentDeclaration ownDeclaration, Type stateType) {

    /*
     * Verify a state has been defined
     */
    if (stateType == null && !ownDeclaration.getGrants().isEmpty()) {
      error("invalid grant expression, state is not defined in composite ");
      return;
    }

    Set<String> grantedStates = new HashSet<String>();
   
    for (GrantDeclaration grantDeclaration : ownDeclaration.getGrants()) {

      // Check that grant state values are valid
      for (String grantState : grantDeclaration.getStates()) {
        if (stateType.value(grantState) == null) {
          error("invalid grant expression, value "+quoted(grantState)+" is not valid for state property "+ quoted(getComposite().getStateProperty().getIdentifier()));
        }
       
        if (grantedStates.contains(grantState)) {
          error("invalid grant expression, state value"+quoted(grantState)+" alreday speciifed in another gran clause "+grantDeclaration);
        }
       
        grantedStates.add(grantState);
      }

      // Check that the granted component exists
      ComponentDeclaration granted  = getComponent(grantDeclaration.getRelation().getDeclaringComponent(),true);

      if (granted == null) {
        error("invalid grant expression, unknown component "+grantDeclaration.getRelation().getDeclaringComponent().getName()+ " in grant expression "+grantDeclaration);
        continue;
      }
     
      // Check that the component is a singleton
      if (granted.isDefinedSingleton()  && ! granted.isSingleton()) {
        warning("invalid grant expression, component "+grantDeclaration.getRelation().getDeclaringComponent().getName()+ " is not a singleton "+grantDeclaration);
      }
     
      // Check that the relation exists and has as target the OWN resource
      // OWN is a specification or an implem but the granted relation can be anything
     
      RelationDeclaration  grantedRelation = granted.getRelation(grantDeclaration.getRelation().getIdentifier());

      if (grantedRelation == null) {
        error("invalid grant expression, the relation "+ quoted(grantDeclaration.getRelation().getIdentifier()) +" is not defined in component " + granted.getName());
      }
      else if (!isCandidateTarget(grantedRelation,owned)) {
        error("invalid grant expression, the relation "+ quoted(grantDeclaration.getRelation().getIdentifier()) +" does not refer to the owned component " + owned.getName());
      }
     
    }
  }
 
  /**
   * Validate the specified state property declaration
   *
   */
  private EnumerationType validateState() {
   
    PropertyDefinition.Reference state = getComposite().getStateProperty();
   
    if (state == null) {
      return null;
    }

    ComponentDeclaration declaring = getComponent(state.getDeclaringComponent(),true);
    if (declaring == null) {
      error("invalid state property "+quoted(state.getIdentifier())+", declaring component "+state.getDeclaringComponent().getName()+" is unavailable");
      return null;
    }
   
    if (! declaring.getKind().equals(ComponentKind.IMPLEMENTATION)) {
      error("invalid state property "+quoted(state.getIdentifier())+", declaring component "+state.getDeclaringComponent().getName()+" is not an implementation");
      return null;
    }
   
    // Attribute state must be defined on the implementation.
    PropertyDefinition property = declaring.getPropertyDefinition(state.getIdentifier());
    if (property == null) {
      error("invalid state property "+quoted(state.getIdentifier())+", not declared in component "+state.getDeclaringComponent().getName());
      return null;
    }

    Type type = getType(property);
    if (!(type instanceof EnumerationType)) {
      error("invalid state property "+quoted(state.getIdentifier())+", must be an enumeration and it is actually of type "+type);
      return null;
    }
   
    return (EnumerationType) type;
  }
 
  /**
   * Cannot check if the component relation is valid. Only checks that the composite relation is declared,
   * and that the component is known.
   *
   * @param composite
   */
  private void validatePromotions() {

    for (RelationPromotion promotion : getComposite().getPromotions()) {
     
      ComponentDeclaration source = getComponent(promotion.getContentRelation().getDeclaringComponent(),true);
      if (source == null) {
        error("invalid promotion, the source component "+ promotion.getContentRelation().getDeclaringComponent() +" is unknown");
      }
     
      RelationDeclaration promotedRelation = source != null ? source.getRelation(promotion.getContentRelation().getIdentifier()) : null;
      // Check if the dependencies are compatible
      if (source != null && promotedRelation == null) {
        error("invalid promotion, the promoted relation "+ quoted(promotion.getContentRelation().getIdentifier()) +" is not defined in component "+source.getName());
        continue;
      }

      RelationDeclaration compositeRelation = getComposite().getRelation(promotion.getCompositeRelation());
      if (compositeRelation == null) {
        error("invalid promotion, the composite relation "+ quoted(promotion.getCompositeRelation().getIdentifier()) +" is not defined");
        continue;
      }

      // Both the composite and the component have a relation with the right id. Check if the targets are compatible
      if (promotedRelation != null && compositeRelation != null && !matchPromotion(promotedRelation, compositeRelation)) {
        error("invalid promotion, the promoted relation "+ quoted(promotion.getContentRelation().getIdentifier()) +
            " does not match the composite relation "  + quoted(promotion.getCompositeRelation().getIdentifier()));
      }
    }
  }

  // Copy paste of the Util class ! too bad, this one uses ApamCapability
  private boolean matchPromotion(RelationDeclaration promotedRelation, RelationDeclaration compositeRelation) {

    boolean match = false;
   
    ComponentDeclaration compositeTarget = getComponent(compositeRelation.getTarget().as(ComponentReference.class),true);
    if (compositeTarget != null) {
      /*
       * If the target of the composite relation is a component, it must satisfy the promoted relation
       */
      match = isCandidateTarget(promotedRelation, compositeTarget);
    }
    else {
      /*
       * Otherwise, the target resource must match exactly
       */
      match = promotedRelation.getTarget().as(ResourceReference.class) != null &&
          promotedRelation.getTarget().equals(compositeRelation.getTarget());
    }
     
    return  match && ( !promotedRelation.isMultiple() || compositeRelation.isMultiple());
  }
 
  private void validateStart() {
    for (InstanceDeclaration instance : getComposite().getInstanceDeclarations()) {
      validate(instance,instanceValidator);
    }
  }

  private void validateContextualRelations() {
   
    for (RelationDeclaration contextual : getComposite().getContextualDependencies()) {
      validate(contextual,contextuallRelationValidator);
    }
   
    for (RelationDeclaration override : getComposite().getOverridenDependencies()) {
      validate(override,contextuallRelationValidator);
    }
   
  }

  protected CompositeDeclaration getComposite() {
    return super.getComponent();
  }
 
  @Override
  protected SpecificationDeclaration getGroup() {
    return (SpecificationDeclaration) super.getGroup();
  }

}
TOP

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

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.