package alien4cloud.utils;
import javax.inject.Inject;
import alien4cloud.tosca.properties.constraints.exception.ConstraintFunctionalException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.alien4cloud.tosca.model.definitions.PropertyDefinition;
import alien4cloud.rest.model.RestErrorBuilder;
import alien4cloud.rest.model.RestErrorCode;
import alien4cloud.rest.model.RestResponse;
import alien4cloud.rest.model.RestResponseBuilder;
import alien4cloud.tosca.properties.constraints.ConstraintUtil;
import alien4cloud.tosca.properties.constraints.exception.ConstraintValueDoNotMatchPropertyTypeException;
import alien4cloud.tosca.properties.constraints.exception.ConstraintViolationException;
import alien4cloud.utils.services.ConstraintPropertyService;
/**
* Rest service that creates a proper REST error from constraint validation.
*/
@Slf4j
@Component
public class RestConstraintValidator {
@Inject
private ConstraintPropertyService constraintPropertyService;
/**
* Performs validation of a property value against it's definition and eventually build a valid rest error in case of violations.
*
* @param propertyName The name of the property to check.
* @param propertyValue The value of the property to check.
* @param propertyDefinition The definition of the property.
* @return Null if no constraints are violated, a RestResponse with validation results in case some constraints are violated.
*/
public RestResponse<ConstraintUtil.ConstraintInformation> validate(final String propertyName, final Object propertyValue,
final PropertyDefinition propertyDefinition) {
if (propertyValue == null || !(propertyValue instanceof String)) {
// by convention updateproperty with null value => reset to default if exists
return null;
}
try {
constraintPropertyService.checkSimplePropertyConstraint(propertyName, (String) propertyValue, propertyDefinition);
} catch (ConstraintFunctionalException e) {
return fromException(e, propertyName, propertyValue);
}
return null;
}
public static RestResponse<ConstraintUtil.ConstraintInformation> fromException(ConstraintFunctionalException ex, String propertyName,
Object propertyValue) {
if (ex instanceof ConstraintViolationException) {
ConstraintViolationException e = (ConstraintViolationException) ex;
log.debug("Constraint violation error for property <" + propertyName + "> with value <" + propertyValue + ">", e);
return RestResponseBuilder.<ConstraintUtil.ConstraintInformation> builder().data(e.getConstraintInformation())
.error(RestErrorBuilder.builder(RestErrorCode.PROPERTY_CONSTRAINT_VIOLATION_ERROR).message(e.getMessage()).build()).build();
} else if (ex instanceof ConstraintValueDoNotMatchPropertyTypeException) {
ConstraintValueDoNotMatchPropertyTypeException e = (ConstraintValueDoNotMatchPropertyTypeException) ex;
log.debug("Constraint value violation error for property <" + e.getConstraintInformation().getName() + "> with value <"
+ e.getConstraintInformation().getValue() + "> and type <" + e.getConstraintInformation().getType() + ">", e);
return RestResponseBuilder.<ConstraintUtil.ConstraintInformation> builder().data(e.getConstraintInformation())
.error(RestErrorBuilder.builder(RestErrorCode.PROPERTY_TYPE_VIOLATION_ERROR).message(e.getMessage()).build()).build();
} else {
throw new IllegalArgumentException("Unexpected ConstraintFunctionalException type", ex);
}
}
}