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 IConstraint {
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    final class Builder
58        extends AbstractConstraintBuilder<Builder, ICardinalityConstraint> {
59      private Integer minOccurs;
60      private Integer maxOccurs;
61  
62      private Builder() {
63        // disable construction
64      }
65  
66      /**
67       * Use the provided minimum occurrence to validate associated targets.
68       *
69       * @param value
70       *          the expected occurrence
71       * @return this builder
72       */
73      public Builder minOccurs(int value) {
74        this.minOccurs = value;
75        return this;
76      }
77  
78      /**
79       * Use the provided maximum occurrence to validate associated targets.
80       *
81       * @param value
82       *          the expected occurrence
83       * @return this builder
84       */
85      public Builder maxOccurs(int value) {
86        this.maxOccurs = value;
87        return this;
88      }
89  
90      @Override
91      protected Builder getThis() {
92        return this;
93      }
94  
95      @Override
96      protected void validate() {
97        super.validate();
98  
99        if (getMinOccurs() == null && getMaxOccurs() == null) {
100         throw new IllegalStateException("At least one of minOccurs or maxOccurs must be provided.");
101       }
102     }
103 
104     private Integer getMinOccurs() {
105       return minOccurs;
106     }
107 
108     private Integer getMaxOccurs() {
109       return maxOccurs;
110     }
111 
112     @Override
113     protected ICardinalityConstraint newInstance() {
114       return new DefaultCardinalityConstraint(
115           getId(),
116           getFormalName(),
117           getDescription(),
118           ObjectUtils.notNull(getSource()),
119           getLevel(),
120           getTarget(),
121           getProperties(),
122           getMinOccurs(),
123           getMaxOccurs(),
124           getRemarks());
125     }
126   }
127 }