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