1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.core.metapath.function;
7   
8   import gov.nist.secauto.metaschema.core.metapath.StaticContext;
9   import gov.nist.secauto.metaschema.core.metapath.StaticMetapathException;
10  import gov.nist.secauto.metaschema.core.metapath.item.IItem;
11  import gov.nist.secauto.metaschema.core.metapath.type.IItemType;
12  import gov.nist.secauto.metaschema.core.metapath.type.ISequenceType;
13  import gov.nist.secauto.metaschema.core.metapath.type.Occurrence;
14  import gov.nist.secauto.metaschema.core.qname.IEnhancedQName;
15  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
16  
17  import java.util.Objects;
18  
19  import edu.umd.cs.findbugs.annotations.NonNull;
20  
21  /**
22   * Represents a single function argument signature.
23   */
24  public interface IArgument {
25    /**
26     * Get the argument's name.
27     *
28     * @return the argument's name
29     */
30    @NonNull
31    String getName();
32  
33    /**
34     * Get information about the type of sequence supported by the argument.
35     *
36     * @return the sequence information
37     */
38    @NonNull
39    ISequenceType getSequenceType();
40  
41    /**
42     * Get the signature of the argument.
43     *
44     * @return the argument's signature
45     */
46    @NonNull
47    String toSignature();
48  
49    /**
50     * Get a new argument builder.
51     *
52     * @return the new argument builder
53     */
54    @NonNull
55    static Builder builder() {
56      return new Builder();
57    }
58  
59    /**
60     * Used to create an argument's signature using a builder pattern.
61     */
62    final class Builder {
63      private String name;
64      @NonNull
65      private IItemType type;
66      private Occurrence occurrence;
67  
68      private Builder() {
69        // construct a new non-initialized builder
70        this.type = IItem.type();
71      }
72  
73      /**
74       * Define the name of the function argument.
75       *
76       * @param name
77       *          the argument's name
78       * @return this builder
79       */
80      @NonNull
81      public Builder name(@NonNull String name) {
82        if (Objects.requireNonNull(name, "name").isBlank()) {
83          throw new IllegalArgumentException("the name must be non-blank");
84        }
85        this.name = name.trim();
86        return this;
87      }
88  
89      /**
90       * Define the type of the function argument.
91       * <p>
92       * By default an argument has the type {@link IItem}.
93       *
94       * @param name
95       *          the qualified name of the argument's type
96       * @return this builder
97       */
98      @NonNull
99      public Builder type(@NonNull IEnhancedQName name) {
100       try {
101         this.type = StaticContext.lookupAtomicType(name);
102       } catch (StaticMetapathException ex) {
103         throw new IllegalArgumentException(
104             String.format("No data type with the name '%s'.", name), ex);
105       }
106       return this;
107     }
108 
109     /**
110      * Define the type of the function argument.
111      * <p>
112      * By default an argument has the type {@link IItem}.
113      *
114      * @param type
115      *          the argument's type
116      * @return this builder
117      */
118     @NonNull
119     public Builder type(@NonNull IItemType type) {
120       this.type = type;
121       return this;
122     }
123 
124     /**
125      * Identifies the argument's cardinality as a single, optional item (zero or
126      * one).
127      *
128      * @return this builder
129      */
130     @NonNull
131     public Builder zeroOrOne() {
132       return occurrence(Occurrence.ZERO_OR_ONE);
133     }
134 
135     /**
136      * Identifies the argument's cardinality as a single, required item (one).
137      *
138      * @return this builder
139      */
140     @NonNull
141     public Builder one() {
142       return occurrence(Occurrence.ONE);
143     }
144 
145     /**
146      * Identifies the argument's cardinality as an optional series of items (zero or
147      * more).
148      *
149      * @return this builder
150      */
151     @NonNull
152     public Builder zeroOrMore() {
153       return occurrence(Occurrence.ZERO_OR_MORE);
154     }
155 
156     /**
157      * Identifies the argument's cardinality as a required series of items (one or
158      * more).
159      *
160      * @return this builder
161      */
162     @NonNull
163     public Builder oneOrMore() {
164       return occurrence(Occurrence.ONE_OR_MORE);
165     }
166 
167     @NonNull
168     private Builder occurrence(@NonNull Occurrence occurrence) {
169       Objects.requireNonNull(occurrence, "occurrence");
170       this.occurrence = occurrence;
171       return this;
172     }
173 
174     /**
175      * Builds the argument's signature.
176      *
177      * @return the argument's signature
178      */
179     @NonNull
180     public IArgument build() {
181       return new ArgumentImpl(
182           ObjectUtils.requireNonNull(name, "the argument name must not be null"),
183           ISequenceType.of(type, ObjectUtils.requireNonNull(occurrence, "occurrence")));
184     }
185   }
186 }