001/*
002 * Portions of this software was developed by employees of the National Institute
003 * of Standards and Technology (NIST), an agency of the Federal Government and is
004 * being made available as a public service. Pursuant to title 17 United States
005 * Code Section 105, works of NIST employees are not subject to copyright
006 * protection in the United States. This software may be subject to foreign
007 * copyright. Permission in the United States and in foreign countries, to the
008 * extent that NIST may hold copyright, to use, copy, modify, create derivative
009 * works, and distribute this software and its documentation without fee is hereby
010 * granted on a non-exclusive basis, provided that this notice and disclaimer
011 * of warranty appears in all copies.
012 *
013 * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER
014 * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY
015 * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM
017 * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE
018 * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE.  IN NO EVENT
019 * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT,
020 * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM,
021 * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
022 * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR
023 * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT
024 * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER.
025 */
026
027package gov.nist.secauto.metaschema.core.model.constraint;
028
029import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine;
030import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline;
031import gov.nist.secauto.metaschema.core.metapath.MetapathExpression;
032import gov.nist.secauto.metaschema.core.metapath.item.atomic.IBooleanItem;
033import gov.nist.secauto.metaschema.core.util.ObjectUtils;
034
035import java.util.LinkedHashMap;
036import java.util.Map;
037import java.util.Set;
038
039import javax.xml.namespace.QName;
040
041import edu.umd.cs.findbugs.annotations.NonNull;
042import edu.umd.cs.findbugs.annotations.Nullable;
043
044public final class DefaultAllowedValuesConstraint
045    extends AbstractConstraint
046    implements IAllowedValuesConstraint {
047  private final boolean allowedOther;
048  @NonNull
049  private final Extensible extensible;
050  @NonNull
051  private final Map<String, DefaultAllowedValue> allowedValues;
052
053  /**
054   * Construct a new allowed values constraint which ensures that a target
055   * instance's value match one of the allowed values. This match is required if
056   * {@link #isAllowedOther()} is {@code false}, otherwise the constraint will
057   * generate a validation warning message if the target instance's value does not
058   * match any of the associated allowed value constraints targeting it.
059   *
060   * the associated test evaluates to {@link IBooleanItem#TRUE} against the
061   * target.
062   *
063   * @param id
064   *          the optional identifier for the constraint
065   * @param formalName
066   *          the constraint's formal name or {@code null} if not provided
067   * @param description
068   *          the constraint's semantic description or {@code null} if not
069   *          provided
070   * @param source
071   *          information about the constraint source
072   * @param level
073   *          the significance of a violation of this constraint
074   * @param target
075   *          the Metapath expression identifying the nodes the constraint targets
076   * @param properties
077   *          a collection of associated properties
078   * @param allowedValues
079   *          the list of allowed values for this constraint
080   * @param allowedOther
081   *          when {@code true} values other than the values specified by
082   *          {@code allowedValues} are allowed, or disallowed if {@code false}
083   * @param extensible
084   *          indicates the degree to which extended values should be allowed
085   * @param remarks
086   *          optional remarks describing the intent of the constraint
087   */
088  private DefaultAllowedValuesConstraint( // NOPMD necessary
089      @Nullable String id,
090      @Nullable String formalName,
091      @Nullable MarkupLine description,
092      @NonNull ISource source,
093      @NonNull Level level,
094      @NonNull MetapathExpression target,
095      @NonNull Map<QName, Set<String>> properties,
096      @NonNull Map<String, DefaultAllowedValue> allowedValues,
097      boolean allowedOther,
098      @NonNull Extensible extensible,
099      @Nullable MarkupMultiline remarks) {
100    super(id, formalName, description, source, level, target, properties, remarks);
101    this.allowedValues = allowedValues;
102    this.allowedOther = allowedOther;
103    this.extensible = extensible;
104  }
105
106  @Override
107  public Map<String, DefaultAllowedValue> getAllowedValues() {
108    return allowedValues;
109  }
110
111  @Override
112  public boolean isAllowedOther() {
113    return allowedOther;
114  }
115
116  @Override
117  public Extensible getExtensible() {
118    return extensible;
119  }
120
121  @Override
122  public <T, R> R accept(IConstraintVisitor<T, R> visitor, T state) {
123    return visitor.visitAllowedValues(this, state);
124  }
125
126  @NonNull
127  public static Builder builder() {
128    return new Builder();
129  }
130
131  public static final class Builder
132      extends AbstractConstraintBuilder<Builder, DefaultAllowedValuesConstraint> {
133    @NonNull
134    private final Map<String, DefaultAllowedValue> allowedValues = new LinkedHashMap<>(); // NOPMD not thread safe
135    private boolean allowedOther = IAllowedValuesConstraint.DEFAULT_ALLOW_OTHER;
136    @NonNull
137    private Extensible extensible = IAllowedValuesConstraint.DEFAULT_EXTENSIBLE;
138
139    private Builder() {
140      // disable construction
141    }
142
143    public Builder allowedValue(@NonNull DefaultAllowedValue allowedValue) {
144      this.allowedValues.put(allowedValue.getValue(), allowedValue);
145      return this;
146    }
147
148    public Builder allowedValues(@NonNull Map<String, DefaultAllowedValue> allowedValues) {
149      this.allowedValues.putAll(allowedValues);
150      return this;
151    }
152
153    public Builder allowedOther(boolean bool) {
154      this.allowedOther = bool;
155      return this;
156    }
157
158    public Builder extensible(@NonNull Extensible extensible) {
159      this.extensible = extensible;
160      return this;
161    }
162
163    @Override
164    protected Builder getThis() {
165      return this;
166    }
167
168    @NonNull
169    protected Map<String, DefaultAllowedValue> getAllowedValues() {
170      return allowedValues;
171    }
172
173    protected boolean isAllowedOther() {
174      return allowedOther;
175    }
176
177    @NonNull
178    protected Extensible getExtensible() {
179      return extensible;
180    }
181
182    @Override
183    protected DefaultAllowedValuesConstraint newInstance() {
184      return new DefaultAllowedValuesConstraint(
185          getId(),
186          getFormalName(),
187          getDescription(),
188          ObjectUtils.notNull(getSource()),
189          getLevel(),
190          getTarget(),
191          getProperties(),
192          getAllowedValues(),
193          isAllowedOther(),
194          getExtensible(),
195          getRemarks());
196    }
197  }
198}