1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.core.model.constraint;
7   
8   import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter;
9   import gov.nist.secauto.metaschema.core.model.constraint.impl.DefaultMatchesConstraint;
10  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
11  
12  import java.util.regex.Pattern;
13  
14  import edu.umd.cs.findbugs.annotations.NonNull;
15  import edu.umd.cs.findbugs.annotations.Nullable;
16  
17  /**
18   * Represents a rule requiring the value of a field or flag to match a pattern
19   * and/or conform to an identified data type.
20   */
21  public interface IMatchesConstraint extends IConfigurableMessageConstraint {
22    /**
23     * Get the expected pattern.
24     *
25     * @return the expected pattern or {@code null} if there is no expected pattern
26     */
27    @Nullable
28    Pattern getPattern();
29  
30    /**
31     * Get the expected data type.
32     *
33     * @return the expected data type or {@code null} if there is no expected data
34     *         type
35     */
36    @Nullable
37    IDataTypeAdapter<?> getDataType();
38  
39    @Override
40    default <T, R> R accept(IConstraintVisitor<T, R> visitor, T state) {
41      return visitor.visitMatchesConstraint(this, state);
42    }
43  
44    /**
45     * Create a new constraint builder.
46     *
47     * @return the builder
48     */
49    @NonNull
50    static Builder builder() {
51      return new Builder();
52    }
53  
54    /**
55     * Provides a builder pattern for constructing a new {@link IMatchesConstraint}.
56     */
57    final class Builder
58        extends AbstractConfigurableMessageConstraintBuilder<Builder, IMatchesConstraint> {
59      private Pattern pattern;
60      private IDataTypeAdapter<?> datatype;
61  
62      private Builder() {
63        // disable construction
64      }
65  
66      /**
67       * Use the provided pattern to validate associated values.
68       *
69       * @param pattern
70       *          the pattern to use
71       * @return this builder
72       */
73      public Builder regex(@NonNull String pattern) {
74        return regex(ObjectUtils.notNull(Pattern.compile(pattern)));
75      }
76  
77      /**
78       * Use the provided pattern to validate associated values.
79       *
80       * @param pattern
81       *          the expected pattern
82       * @return this builder
83       */
84      public Builder regex(@NonNull Pattern pattern) {
85        this.pattern = pattern;
86        return this;
87      }
88  
89      /**
90       * Use the provided data type to validate associated values.
91       *
92       * @param datatype
93       *          the expected data type
94       * @return this builder
95       */
96      public Builder datatype(@NonNull IDataTypeAdapter<?> datatype) {
97        this.datatype = datatype;
98        return this;
99      }
100 
101     @Override
102     protected Builder getThis() {
103       return this;
104     }
105 
106     @Override
107     protected void validate() {
108       super.validate();
109 
110       if (getPattern() == null && getDatatype() == null) {
111         throw new IllegalStateException("A pattern or data type must be provided at minimum.");
112       }
113     }
114 
115     private Pattern getPattern() {
116       return pattern;
117     }
118 
119     private IDataTypeAdapter<?> getDatatype() {
120       return datatype;
121     }
122 
123     @Override
124     protected IMatchesConstraint newInstance() {
125       return new DefaultMatchesConstraint(
126           getId(),
127           getFormalName(),
128           getDescription(),
129           ObjectUtils.notNull(getSource()),
130           getLevel(),
131           getTarget(),
132           getProperties(),
133           getPattern(),
134           getDatatype(),
135           getMessage(),
136           getRemarks());
137     }
138   }
139 }