IAllowedValuesConstraint.java
/*
* SPDX-FileCopyrightText: none
* SPDX-License-Identifier: CC0-1.0
*/
package gov.nist.secauto.metaschema.core.model.constraint;
import gov.nist.secauto.metaschema.core.model.constraint.impl.DefaultAllowedValuesConstraint;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import java.util.LinkedHashMap;
import java.util.Map;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
/**
* Represents a rule requiring the value of a field or flag to match the name of
* one entry in a set of enumerated values.
*/
public interface IAllowedValuesConstraint extends IConstraint {
/**
* The default allow other value.
*/
boolean ALLOW_OTHER_DEFAULT = false;
/**
* The default extensible value.
*/
@NonNull
Extensible EXTENSIBLE_DEFAULT = Extensible.EXTERNAL;
/**
* Indicates how an allowed values constraint can be extended, or if it can be.
*/
enum Extensible {
/**
* Can be extended by external constraints. The most permissive level.
*/
EXTERNAL,
/**
* Can be extended by constraints in the same model.
*/
MODEL,
/**
* Cannot be extended. The most restrictive level.
*/
NONE;
}
/**
* Get the collection allowed values associated with this constraint.
*
* @return a mapping of value to the associated {@link IAllowedValue} item
*/
@NonNull
Map<String, ? extends IAllowedValue> getAllowedValues();
/**
* Get a specific allowed value by name, if it is defined for this constraint.
*
* @param name
* the value name
* @return the allowed value or {@code null} if the value is not defined
*/
@Nullable
default IAllowedValue getAllowedValue(String name) {
return getAllowedValues().get(name);
}
/**
* Determines if this allowed value constraint is open-ended ({@code true}) or
* closed. If "open-ended", the constraint allows the target's value to by any
* additional unspecified value. If "closed", the constraint requries the
* target's value to be one of the specified values.
*
* @return {@code true} if the constraint is "open-ended", or {@code false}
* otherwise
*/
boolean isAllowedOther();
/**
* Determines the degree to which this constraint can be extended by other
* constraints applied to the same value.
*
* @return the enumeration value
*/
@NonNull
Extensible getExtensible();
@Override
default <T, R> R accept(IConstraintVisitor<T, R> visitor, T state) {
return visitor.visitAllowedValues(this, state);
}
/**
* Create a new constraint builder.
*
* @return the builder
*/
@NonNull
static Builder builder() {
return new Builder();
}
/**
* Provides a builder pattern for constructing a new
* {@link IAllowedValuesConstraint}.
*/
final class Builder
extends AbstractConstraintBuilder<Builder, IAllowedValuesConstraint> {
@NonNull
private final Map<String, IAllowedValue> allowedValues = new LinkedHashMap<>(); // NOPMD not thread safe
private boolean allowedOther = ALLOW_OTHER_DEFAULT;
@NonNull
private Extensible extensible = EXTENSIBLE_DEFAULT;
private Builder() {
// disable construction
}
/**
* Use the provided allowed value to validate associated values.
*
* @param allowedValue
* an expected allowed value
* @return this builder
*/
@NonNull
public Builder allowedValue(@NonNull IAllowedValue allowedValue) {
this.allowedValues.put(allowedValue.getValue(), allowedValue);
return this;
}
/**
* Use the provided allowed values to validate associated values.
*
* @param allowedValues
* an expected allowed values
* @return this builder
*/
@NonNull
public Builder allowedValues(@NonNull Map<String, IAllowedValue> allowedValues) {
this.allowedValues.putAll(allowedValues);
return this;
}
/**
* Determine if unspecified values are allowed and will result in the constraint
* always passing.
*
* @param bool
* {@code true} if other values are allowed or {@code false} otherwise
* @return this builder
*/
@NonNull
public Builder allowsOther(boolean bool) {
this.allowedOther = bool;
return this;
}
/**
* Determine the allowed scope of extension for other constraints matching this
* constraint's target.
*
* @param extensible
* the degree of allowed extension
* @return this builder
*/
@NonNull
public Builder extensible(@NonNull Extensible extensible) {
this.extensible = extensible;
return this;
}
@Override
protected Builder getThis() {
return this;
}
@NonNull
private Map<String, IAllowedValue> getAllowedValues() {
return allowedValues;
}
private boolean isAllowedOther() {
return allowedOther;
}
@NonNull
private Extensible getExtensible() {
return extensible;
}
@Override
protected IAllowedValuesConstraint newInstance() {
return new DefaultAllowedValuesConstraint(
getId(),
getFormalName(),
getDescription(),
ObjectUtils.notNull(getSource()),
getLevel(),
getTarget(),
getProperties(),
getAllowedValues(),
isAllowedOther(),
getExtensible(),
getRemarks());
}
}
}