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

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

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

import java.util.Collection;

import fr.imag.adele.apam.declarations.ComponentDeclaration;
import fr.imag.adele.apam.declarations.ConstrainedReference;
import fr.imag.adele.apam.declarations.PropertyDefinition;
import fr.imag.adele.apam.declarations.references.Reference;
import fr.imag.adele.apam.declarations.references.ResolvableReference;
import fr.imag.adele.apam.declarations.references.components.ComponentReference;
import fr.imag.adele.apam.declarations.references.resources.ResourceReference;
import fr.imag.adele.apam.maven.plugin.validation.property.CollectionType;
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.Attribute;

/**
* The common validation for constrained referenced defined in components
*
* @author vega
*
*/
public class ConstrainedReferenceValidator<R extends ConstrainedReference> extends AbstractValidator<R,Void> {

  /**
   * The parser used to validate all defined property types
   */
  private final TypeParser           typeParser;

  /**
   * The validator used to validate substitution expressions
   */
  private final ContextualExpressionValidator expressionValidator;
 
  public ConstrainedReferenceValidator(ComponentValidator<?> parent) {
    super(parent);

    this.typeParser        = new TypeParser();
    this.expressionValidator  = new ContextualExpressionValidator(this,typeParser);
  }

  public Void validate(R reference) {
    initializeState(reference);
   
    validateTarget();
    validateConstraints();

    return null;
  }

  /**
   * validate the target of the reference
   */
  protected void validateTarget() {
   
    if (getTargetReference() == null) {
      return;
    }
    else if (targetIsComponent() && getTarget() == null) {
      error("the specified target component "+getTargetReference().getName()+ " is not available");
    }
    else if (targetIsResource()) {
      checkResourceExists(getTargetReference(ResourceReference.class));
    }
  }

  /**
   * validate the associated constraints
   */
  protected void validateConstraints() {
   
    validate(getReference().getImplementationConstraints(),"error in Implementation constraints");
    validate(getReference().getImplementationPreferences(),"error in Implementation preferences");
    validate(getReference().getInstanceConstraints(),"error in Instance constraints");
    validate(getReference().getInstancePreferences(),"error in Instance preferences");
  }

  /**
   * Parses the specified type
   */
  protected Type getType(PropertyDefinition property) {
    return typeParser.parse(property.getType());
  }
 
  /**
   * Validates the specified filter collection
   */
  private void validate(Collection<String> filters, String message) {
    for (String filter : filters) {
      validate(filter,message);
    }
  }

  /**
   * Validates the specified filter
   */
  private void validate(String filter, String message) {
   
    /*
     * validate syntax
     */
    ApamFilter expression = parseFilter(filter);
    if (expression == null) {
      error(message+", invalid filter syntax "+quoted(filter));
      return;
    }
   
    /*
     * validate typing
     */
    validate(expression,message);
  }
 
  /**
   * Validates the specified filter
   */
  private void validate(ApamFilter expression, String message) {
    initializeFilter(expression);
    switch (expression.op) {
     
      case ApamFilter.AND:
      case ApamFilter.OR:
       
        /*
         * validate filters of sub-expression
         */
        for (ApamFilter subExpression : ((ApamFilter[]) expression.value)) {
          validate(subExpression,message);
        }
        break;

      case ApamFilter.NOT:
        /*
         * validate filters of sub-expression
         */
        validate((ApamFilter)expression.value,message);
        break;
       
      case ApamFilter.SUBSTRING:
      case ApamFilter.EQUAL:
      case ApamFilter.GREATER:
      case ApamFilter.LESS:
      case ApamFilter.APPROX:
      case ApamFilter.SUBSET:
      case ApamFilter.SUPERSET:
      case ApamFilter.PRESENT:
        /*
         * validate attribute comparison expression
         */
        validate(expression.op,expression.attr,getValue(expression),message);
        break;
    }
    resetFilter();
  }

  /**
   * Validates the specified attribute comparison expression is valid
   */
  private void validate(int operation, String propertyName, String value, String message) {

    if (targetIsResource()) {
      warning(message+", substitute expression "+quoted(filter.toString())+ " cannot be completely validated at build-time");
    }

    /*
     * Validate property is well defined
     */
    PropertyDefinition property = getTarget() != null ? getTarget().getPropertyDefinition(propertyName) : null;
   
    if (getTarget() != null) {
     
      if (property == null && !Attribute.isFinalAttribute(propertyName)) {
        error(message+", invalid filter "+quoted(filter.toString())+", the property "+quoted(propertyName)+ " is not defined in component "+getTarget().getName());
      }
     
      if (property != null && property.getDefaultValue() != null && expressionValidator.isContextualExpression(property.getDefaultValue())) {
        error(message+", invalid filter "+quoted(filter.toString())+", the property "+quoted(propertyName)+ " can not be used in filters because it is a substitution "+quoted(property.getDefaultValue()));
      }
    }

    /*
     * check value is valid with respect to the type of the property
     */
   
    if (value == null)
      return;

    Type propertyType   = property != null ? getType(property) : null;

    if (expressionValidator.isContextualExpression(value)) {
     
      /*
       * If the value is a substitution expression try to parse and type it.  Verify the type of the
       * expression is comparable to the type of the property
       *
       * TODO We need to validate what are the automatic conversions performed by the filter at runtime
       */
      Type expressionType  = validate(value,expressionValidator);
     
      if (expressionType != null && propertyType != null &&
        !expressionType.isAssignableTo(propertyType) && !propertyType.isAssignableTo(expressionType)) {
        error(message+", invalid filter "+quoted(filter.toString())+", the property "+quoted(propertyName)+ " has type "+propertyType+" and the value "+quoted(value)+" has type "+expressionType);
      }
     
    }
    else {

      /*
       * Operators involving sets perform automatic conversion of the property to a collection
       */
      if (operation == ApamFilter.SUBSET || operation == ApamFilter.SUPERSET) {
        if (propertyType != null && !(propertyType instanceof CollectionType)) {
          propertyType = new CollectionType(propertyType, false);
        }
      }
     
      /*
       * If the property is a collection, the equality operator is overloaded to mean set containment
       */
      if (operation == ApamFilter.EQUAL && propertyType != null && propertyType instanceof CollectionType) {
        propertyType = ((CollectionType)propertyType).getElementType();
      }

     
      /*
       * For normal values, just validates the literal is accepted by the type
       */
      if (propertyType != null && propertyType.value(value) == null) {
        error(message+", invalid filter "+quoted(filter.toString())+", the value "+quoted(value)+" is not valid for the expected type "+quoted(propertyType.getName()));
      }
    }

  }


  /**
   * The declaration being validated
   */
  private R reference;

  /**
   * The target component, if defined
   */
  private ComponentDeclaration target;
 
  /**
   * The filter being validated
   */
  private ApamFilter filter;
 
  /**
   * Initializes the state of this validator
   */
  protected void initializeState(R reference) {
    this.reference = reference;
   
    /*
     * try to load the target component, if any
     */
    this.target    = getComponent(getTargetReference(ComponentReference.class),true);
   
  }

  protected void initializeFilter(ApamFilter filter) {
    this.filter = filter;
  }
 
 
  /**
   * The constrained reference declaration that is being validated
   */
  protected R getReference() {
    return reference;
  }
 
  /**
   * The referenced target
   */
  protected ResolvableReference getTargetReference() {
    return getReference().getTarget();
  }

  /**
   * The referenced target cast to the appropriate type
   */
  protected <T extends Reference> T getTargetReference(Class<T> kind) {
    return kind.isInstance(getTargetReference()) ? kind.cast(getTargetReference()) : null;
  }

  /**
   * Determines if the target is a resource
   */
  protected boolean targetIsResource() {
    return getTargetReference() != null && getTargetReference(ResourceReference.class) !=null;
  }
 
  /**
   * Determines if the target is a resource
   */
  protected boolean targetIsComponent() {
    return getTargetReference() != null && getTargetReference(ComponentReference.class) !=null;
  }
 
 
  /**
   * The component target of the current declaration, if one is explicitly defined and is available
   * on the repository
   */
  protected ComponentDeclaration getTarget() {
    return target;
  }
 

  public void resetFilter() {
    this.filter = null;
  }
 
  /**
   * Frees all references to the state of validation
   */
  @Override
  public void resetState() {
    this.reference   = null;
    super.resetState();
  }

  /**
   * Get the encoded value of an attribute in a comparison expression.
   */
  private static String getValue(ApamFilter expression) {
    /*
     * For operations not involving a pattern just return the parsed value
     */
    if (expression.op != ApamFilter.SUBSTRING)
      return (String) expression.value;
    /*
     * for pattern matching rebuild the pattern from the parsed values
     */
    String[] substrings = (String[]) expression.value;
    StringBuilder pattern = new StringBuilder();
    for (String substr : substrings) {
      if (substr == null) /* wildcard */{
        pattern.append('*');
      } else /* text */{
        pattern.append(ApamFilter.encodeValue(substr));
      }
    }
    return pattern.toString();
  }

}
TOP

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

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.