001/*
002 * SPDX-FileCopyrightText: none
003 * SPDX-License-Identifier: CC0-1.0
004 */
005
006package dev.metaschema.core.model;
007
008import java.util.Collection;
009
010import dev.metaschema.core.qname.IEnhancedQName;
011import dev.metaschema.core.util.CollectionUtil;
012import dev.metaschema.core.util.ObjectUtils;
013import edu.umd.cs.findbugs.annotations.NonNull;
014import edu.umd.cs.findbugs.annotations.Nullable;
015
016/**
017 * This behavioral interface represents an instance that supports grouped
018 * values.
019 */
020public interface IGroupable extends IInstance {
021
022  /**
023   * The default Metaschema grouping minimum occurrence.
024   */
025  int DEFAULT_GROUP_AS_MIN_OCCURS = 0;
026  /**
027   * The default Metaschema grouping maximum occurrence.
028   */
029  int DEFAULT_GROUP_AS_MAX_OCCURS = 1;
030  /**
031   * The default Metaschema grouping behavior for JSON data.
032   */
033  @NonNull
034  JsonGroupAsBehavior DEFAULT_JSON_GROUP_AS_BEHAVIOR = JsonGroupAsBehavior.SINGLETON_OR_LIST;
035  /**
036   * The default Metaschema grouping behavior for XML data.
037   */
038  @NonNull
039  XmlGroupAsBehavior DEFAULT_XML_GROUP_AS_BEHAVIOR = XmlGroupAsBehavior.UNGROUPED;
040
041  /**
042   * Get the minimum cardinality for this associated instance. This value must be
043   * less than or equal to the maximum cardinality returned by
044   * {@link #getMaxOccurs()}.
045   *
046   * @return {@code 0} or a positive integer value
047   * @see #DEFAULT_GROUP_AS_MIN_OCCURS
048   */
049  int getMinOccurs();
050
051  /**
052   * Get the maximum cardinality for this associated instance. This value must be
053   * greater than or equal to the minimum cardinality returned by
054   * {@link #getMinOccurs()}, or {@code -1} if unbounded.
055   *
056   * @return a positive integer value or {@code -1} if unbounded
057   * @see #DEFAULT_GROUP_AS_MAX_OCCURS
058   */
059  int getMaxOccurs();
060
061  /**
062   * Get the name provided for grouping. An instance in Metaschema must have a
063   * group name if the instance has a cardinality greater than {@code 1}.
064   *
065   * @return the group-as name or {@code null} if no name is configured, such as
066   *         when {@link #getMaxOccurs()} = 1
067   */
068  @Nullable
069  default String getGroupAsName() {
070    // no group-as by default
071    return null;
072  }
073
074  /**
075   * Get the name used for the associated element wrapping a collection of
076   * elements in XML. This value is required when {@link #getXmlGroupAsBehavior()}
077   * = {@link XmlGroupAsBehavior#GROUPED}. This name will be the element name
078   * wrapping a collection of elements.
079   * <p>
080   * If this instance doesn't have a namespace defined, then the module's XML
081   * namespace will be used.
082   *
083   * @return the groupAs QName or {@code null} if no name is configured, such as
084   *         when {@link #getMaxOccurs()} = 1.
085   */
086  @Nullable
087  default IEnhancedQName getEffectiveXmlGroupAsQName() {
088    return getXmlGroupAsBehavior() == XmlGroupAsBehavior.GROUPED
089        ? IEnhancedQName.of(
090            getContainingDefinition().getQName().getNamespace(),
091            ObjectUtils.requireNonNull(getGroupAsName()))
092        : null;
093  }
094
095  /**
096   * Gets the configured JSON group-as strategy. A JSON group-as strategy is only
097   * required when {@link #getMaxOccurs()} &gt; 1.
098   * <p>
099   * The default for this method is {@link JsonGroupAsBehavior#NONE}, since the
100   * default behavior is to have no grouping. If {@link #getMaxOccurs()} is
101   * greater than {@code 1}, then the default behavior is
102   * {@code #DEFAULT_JSON_GROUP_AS_BEHAVIOR}.
103   *
104   * @return the JSON group-as strategy, or {@code JsonGroupAsBehavior#NONE} if
105   *         {@link #getMaxOccurs()} = 1
106   * @see #DEFAULT_JSON_GROUP_AS_BEHAVIOR
107   */
108  @NonNull
109  default JsonGroupAsBehavior getJsonGroupAsBehavior() {
110    return JsonGroupAsBehavior.NONE;
111  }
112
113  /**
114   * Gets the configured XML group-as strategy. A XML group-as strategy is only
115   * required when {@link #getMaxOccurs()} &gt; 1.
116   *
117   * @return the JSON group-as strategy, or {@code XmlGroupAsBehavior#UNGROUPED}
118   *         if {@link #getMaxOccurs()} = 1
119   * @see #DEFAULT_XML_GROUP_AS_BEHAVIOR
120   */
121  @NonNull
122  default XmlGroupAsBehavior getXmlGroupAsBehavior() {
123    return DEFAULT_XML_GROUP_AS_BEHAVIOR;
124  }
125
126  /**
127   * Get the item values for the provided {@code instanceValue}. An instance may
128   * be singular or many valued.
129   *
130   * @param instanceValue
131   *          the instance
132   * @return the item values or an empty collection if no item values exist
133   */
134  @NonNull
135  default Collection<?> getItemValues(@NonNull Object instanceValue) {
136    // no item values by default
137    return CollectionUtil.emptyList();
138  }
139}