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.model.IModelInstanceAbsolute;
9   import gov.nist.secauto.metaschema.core.model.constraint.impl.DefaultCardinalityConstraint;
10  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
11  
12  import edu.umd.cs.findbugs.annotations.NonNull;
13  import edu.umd.cs.findbugs.annotations.Nullable;
14  
15  /**
16   * Represents a rule requiring a Metaschema assembly data instance to have
17   * elements with a minimum and/or maximum occurrence.
18   */
19  public interface ICardinalityConstraint extends IConfigurableMessageConstraint {
20    /**
21     * Retrieve the required minimum occurrence of the target instance. If
22     * specified, this value must be less than or equal to the value of
23     * {@link IModelInstanceAbsolute#getMaxOccurs()} and greater than
24     * {@link IModelInstanceAbsolute#getMinOccurs()}.
25     *
26     * @return a non-negative integer or {@code null} if not defined
27     */
28    @Nullable
29    Integer getMinOccurs();
30  
31    /**
32     * Retrieve the required maximum occurrence of the target instance. If
33     * specified, this value must be less than the value of
34     * {@link IModelInstanceAbsolute#getMaxOccurs()} and greater than or equal to
35     * {@link IModelInstanceAbsolute#getMinOccurs()}.
36     *
37     * @return a non-negative integer or {@code null} if not defined
38     */
39    @Nullable
40    Integer getMaxOccurs();
41  
42    @Override
43    default <T, R> R accept(IConstraintVisitor<T, R> visitor, T state) {
44      return visitor.visitCardinalityConstraint(this, state);
45    }
46  
47    /**
48     * Create a new constraint builder.
49     *
50     * @return the builder
51     */
52    @NonNull
53    static Builder builder() {
54      return new Builder();
55    }
56  
57    /**
58     * Provides a builder pattern for constructing a new
59     * {@link ICardinalityConstraint}.
60     */
61    final class Builder
62        extends AbstractConfigurableMessageConstraintBuilder<Builder, ICardinalityConstraint> {
63      private Integer minOccurs;
64      private Integer maxOccurs;
65  
66      private Builder() {
67        // disable construction
68      }
69  
70      /**
71       * Use the provided minimum occurrence to validate associated targets.
72       *
73       * @param value
74       *          the expected occurrence
75       * @return this builder
76       */
77      public Builder minOccurs(int value) {
78        this.minOccurs = value;
79        return this;
80      }
81  
82      /**
83       * Use the provided maximum occurrence to validate associated targets.
84       *
85       * @param value
86       *          the expected occurrence
87       * @return this builder
88       */
89      public Builder maxOccurs(int value) {
90        this.maxOccurs = value;
91        return this;
92      }
93  
94      @Override
95      protected Builder getThis() {
96        return this;
97      }
98  
99      @Override
100     protected void validate() {
101       super.validate();
102 
103       if (getMinOccurs() == null && getMaxOccurs() == null) {
104         throw new IllegalStateException("At least one of minOccurs or maxOccurs must be provided.");
105       }
106     }
107 
108     private Integer getMinOccurs() {
109       return minOccurs;
110     }
111 
112     private Integer getMaxOccurs() {
113       return maxOccurs;
114     }
115 
116     @Override
117     protected ICardinalityConstraint newInstance() {
118       return new DefaultCardinalityConstraint(
119           getId(),
120           getFormalName(),
121           getDescription(),
122           ObjectUtils.notNull(getSource()),
123           getLevel(),
124           getTarget(),
125           getProperties(),
126           getMinOccurs(),
127           getMaxOccurs(),
128           getMessage(),
129           getRemarks());
130     }
131   }
132 }