package org.alien4cloud.tosca.model.definitions;
import java.util.ArrayList;
import java.util.List;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import alien4cloud.model.components.IncompatiblePropertyDefinitionException;
import org.elasticsearch.annotation.BooleanField;
import org.elasticsearch.annotation.ObjectField;
import org.elasticsearch.annotation.StringField;
import org.elasticsearch.mapping.IndexType;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import alien4cloud.json.deserializer.PropertyConstraintDeserializer;
import alien4cloud.json.deserializer.PropertyValueDeserializer;
import org.alien4cloud.tosca.model.definitions.constraints.*;
import alien4cloud.tosca.container.validation.*;
import alien4cloud.ui.form.annotation.FormContentTypes;
import alien4cloud.ui.form.annotation.FormProperties;
import alien4cloud.ui.form.annotation.FormType;
import alien4cloud.ui.form.annotation.FormValidValues;
import lombok.*;
/**
*
* Only parameter exposed as property definitions can be used for "custom" operations.
*
* @author 'Igor Ngouagna'
*
*/
@Getter
@Setter
@NoArgsConstructor
@EqualsAndHashCode(of = { "type", "required", "description", "defaultValue", "constraints", "entrySchema" })
@ToscaPropertyDefaultValueType
@ToscaPropertyConstraint
@ToscaPropertyDefaultValueConstraints(groups = { ToscaPropertyPostValidationGroup.class })
@JsonIgnoreProperties(ignoreUnknown = true)
@FormProperties({ "type", "required", "default", "description" })
@ToString
public class PropertyDefinition implements IValue {
@StringField(indexType = IndexType.not_analyzed)
@ToscaPropertyType
@FormValidValues({ "boolean", "string", "float", "integer", "version" })
@NotNull
private String type;
@ObjectField(enabled = false)
private PropertyDefinition entrySchema;
@NotNull
@BooleanField(index = IndexType.no)
private boolean required = true;
@JsonProperty("default")
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
private PropertyValue defaultValue;
@StringField(indexType = IndexType.no)
private String description;
@StringField(indexType = IndexType.no)
private String suggestionId;
@ObjectField(enabled = false)
@Valid
@ToscaPropertyConstraintDuplicate
@JsonDeserialize(contentUsing = PropertyConstraintDeserializer.class)
@FormContentTypes({ @FormType(discriminantProperty = "equal", label = "CONSTRAINT.EQUAL", implementation = EqualConstraint.class),
@FormType(discriminantProperty = "greaterThan", label = "CONSTRAINT.GREATER_THAN", implementation = GreaterThanConstraint.class),
@FormType(discriminantProperty = "greaterOrEqual", label = "CONSTRAINT.GREATER_OR_EQUAL", implementation = GreaterOrEqualConstraint.class),
@FormType(discriminantProperty = "lessThan", label = "CONSTRAINT.LESS_THAN", implementation = LessThanConstraint.class),
@FormType(discriminantProperty = "lessOrEqual", label = "CONSTRAINT.LESS_OR_EQUAL", implementation = LessOrEqualConstraint.class),
@FormType(discriminantProperty = "inRange", label = "CONSTRAINT.IN_RANGE", implementation = InRangeConstraint.class),
@FormType(discriminantProperty = "length", label = "CONSTRAINT.LENGTH", implementation = LengthConstraint.class),
@FormType(discriminantProperty = "maxLength", label = "CONSTRAINT.MAX_LENGTH", implementation = MaxLengthConstraint.class),
@FormType(discriminantProperty = "minLength", label = "CONSTRAINT.MIN_LENGTH", implementation = MinLengthConstraint.class),
@FormType(discriminantProperty = "pattern", label = "CONSTRAINT.PATTERN", implementation = PatternConstraint.class),
@FormType(discriminantProperty = "validValues", label = "CONSTRAINT.VALID_VALUES", implementation = ValidValuesConstraint.class) })
private List<PropertyConstraint> constraints;
@BooleanField(index = IndexType.no)
private boolean isPassword;
public PropertyDefinition(PropertyDefinition from) {
this.type = from.type;
this.entrySchema = from.entrySchema;
this.required = from.required;
this.defaultValue = from.defaultValue;
this.description = from.description;
this.suggestionId = from.suggestionId;
this.constraints = from.constraints;
this.isPassword = from.isPassword;
}
@JsonDeserialize(using = PropertyValueDeserializer.class)
@ObjectField(enabled = false)
public PropertyValue getDefault() {
return this.defaultValue;
}
public void setDefault(PropertyValue defaultValue) {
this.defaultValue = defaultValue;
}
@Override
public boolean isDefinition() {
return true;
}
/**
* Check if all constraint are equals
*
* @param propertyDefinition
* @throws IncompatiblePropertyDefinitionException
*/
public void checkIfCompatibleOrFail(final PropertyDefinition propertyDefinition) throws IncompatiblePropertyDefinitionException {
if (propertyDefinition == null) {
throw new IncompatiblePropertyDefinitionException();
} else if (!this.getType().equals(propertyDefinition.getType())) {
throw new IncompatiblePropertyDefinitionException();
} else if (this.getConstraints() == null && propertyDefinition.getConstraints() == null) {
return;
} else if (this.getConstraints() == null || propertyDefinition.getConstraints() == null
|| this.getConstraints().size() != propertyDefinition.getConstraints().size()) {
throw new IncompatiblePropertyDefinitionException();
}
ArrayList<PropertyConstraint> copyOfOtherConstraints = new ArrayList<PropertyConstraint>(propertyDefinition.getConstraints());
for (PropertyConstraint constraint : this.getConstraints()) {
for (int i = 0; i <= copyOfOtherConstraints.size(); i++) {
if (copyOfOtherConstraints.size() == 0) { // If all elements are compatible
return;
} else if (i == copyOfOtherConstraints.size()) { // If the constraint is not compatible with an constraint from the other PropertyDefinition
throw new IncompatiblePropertyDefinitionException();
} else if (constraint.equals(copyOfOtherConstraints.get(i))) { // If the two constraints are compatible
copyOfOtherConstraints.remove(i); // we remove the constraint in the copy of the other propertyDefinition constraints and continue
break;
}
}
}
}
}