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