001/*
002 *    GeoAPI - Java interfaces for OGC/ISO standards
003 *    Copyright © 2022-2024 Open Geospatial Consortium, Inc.
004 *    http://www.geoapi.org
005 *
006 *    Licensed under the Apache License, Version 2.0 (the "License");
007 *    you may not use this file except in compliance with the License.
008 *    You may obtain a copy of the License at
009 *
010 *        http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *    Unless required by applicable law or agreed to in writing, software
013 *    distributed under the License is distributed on an "AS IS" BASIS,
014 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 *    See the License for the specific language governing permissions and
016 *    limitations under the License.
017 */
018package org.opengis.metadata.quality;
019
020import java.util.Map;
021import java.util.Set;
022import java.util.List;
023import java.util.Collection;
024import java.util.Optional;
025import org.opengis.util.CodeList;
026import org.opengis.annotation.UML;
027import org.opengis.referencing.operation.Matrix;
028import org.opengis.geoapi.internal.Vocabulary;
029
030import static org.opengis.annotation.Obligation.*;
031import static org.opengis.annotation.Specification.*;
032
033
034/**
035 * Structure for reporting a complex data quality result.
036 *
037 * @author  Alexis Gaillard (Geomatys)
038 * @author  Martin Desruisseaux (Geomatys)
039 * @version 3.1
040 * @since   3.1
041 */
042@Vocabulary(capacity=6, parameters=1)
043@UML(identifier="DQM_ValueStructure", specification=ISO_19157)
044public final class ValueStructure extends CodeList<ValueStructure> {
045    /**
046     * Serial number for compatibility with different versions.
047     */
048    private static final long serialVersionUID = 455647811714853262L;
049
050    /**
051     * Finite, unordered collection of related items that may be repeated.
052     * The corresponding Java type is {@link java.util.Collection}.
053     */
054    @UML(identifier="bag", obligation=CONDITIONAL, specification=ISO_19157)
055    public static final ValueStructure BAG = new ValueStructure("BAG", Collection.class);
056
057    /**
058     * Unordered collection of related items with no repetition.
059     * The corresponding Java type is {@link java.util.Set}.
060     */
061    @UML(identifier="set", obligation=CONDITIONAL, specification=ISO_19157)
062    public static final ValueStructure SET = new ValueStructure("SET", Set.class);
063
064    /**
065     * Finite, ordered collection of related items that may be repeated.
066     * The corresponding Java type is {@link java.util.List}.
067     */
068    @UML(identifier="sequence", obligation=CONDITIONAL, specification=ISO_19157)
069    public static final ValueStructure SEQUENCE = new ValueStructure("SEQUENCE", List.class);
070
071    /**
072     * An arrangement of data in which each item may be identified by means of arguments or keys.
073     * The corresponding Java type is {@link java.util.Map}.
074     */
075    @UML(identifier="table", obligation=CONDITIONAL, specification=ISO_19157)
076    public static final ValueStructure TABLE = new ValueStructure("TABLE", Map.class);
077
078    /**
079     * Rectangular array of numbers.
080     * The corresponding Java type is {@link org.opengis.referencing.operation.Matrix}.
081     */
082    @UML(identifier="matrix", obligation=CONDITIONAL, specification=ISO_19157)
083    public static final ValueStructure MATRIX = new ValueStructure("MATRIX", Matrix.class);
084
085    /**
086     * Feature that acts as a function to return values from its range
087     * for any direct position within its spatial, temporal or spatiotemporal domain.
088     */
089    @UML(identifier="coverage", obligation=CONDITIONAL, specification=ISO_19157)
090    public static final ValueStructure COVERAGE = new ValueStructure("COVERAGE");
091
092    /**
093     * The values in the order they should be tested by {@link #valueOf(Class)}.
094     * In particular, {@link #SEQUENCE} and {@link #SET} shall be tested before {@link #BAG}.
095     */
096    private static final ValueStructure[] PREDEFINED = {SEQUENCE, SET, TABLE, BAG, MATRIX};
097
098    /**
099     * Base Java type for objects storing this kind of structure, or {@code null} if unspecified.
100     */
101    private final Class<?> type;
102
103    /**
104     * Constructs an element of the given name.
105     *
106     * This is invoked by reflection by {@link #valueOf(Class, String)}
107     * when a new code needs to be created. This is indirectly required
108     * for {@link #valueOf(String)} implementation.
109     *
110     * @param name  the name of the new element. This name shall not be in use by another element of this type.
111     */
112    private ValueStructure(final String name) {
113        super(name);
114        type = null;
115    }
116
117    /**
118     * Constructs an element of the given name.
119     *
120     * @param name  the name of the new element. This name shall not be in use by another element of this type.
121     * @param type  base Java interface for objects storing this kind of structure.
122     */
123    private ValueStructure(final String name, final Class<?> type) {
124        super(name);
125        this.type = type;
126    }
127
128    /**
129     * Returns the list of {@code ValueStructure}s.
130     *
131     * @return the list of codes declared in the current JVM.
132     */
133    public static ValueStructure[] values() {
134        return values(ValueStructure.class);
135    }
136
137    /**
138     * Returns the list of codes of the same kind as this code list element.
139     * Invoking this method is equivalent to invoking {@link #values()}, except that
140     * this method can be invoked on an instance of the parent {@code CodeList} class.
141     *
142     * @return all code {@linkplain #values() values} for this code list.
143     */
144    @Override
145    public ValueStructure[] family() {
146        return values();
147    }
148
149    /**
150     * Returns the structure that matches the given string, or returns a new one if none match it.
151     * This methods returns the first instance (in declaration order) for which the {@linkplain #name() name}
152     * is {@linkplain String#equalsIgnoreCase(String) equals, ignoring case}, to the given name.
153     * If no existing instance is found, then a new one is created for the given name.
154     *
155     * @param  code  the name of the code to fetch or to create.
156     * @param  type  Java type corresponding to the value, or {@code null} if unspecified.
157     *               This is used only if a new code list element is created.
158     * @return a code matching the given name.
159     */
160    public static ValueStructure valueOf(String code, final Class<?> type) {
161        return valueOf(ValueStructure.class, code, (name) -> new ValueStructure(name, type)).get();
162    }
163
164    /**
165     * Returns the structure corresponding to the given class.
166     * The mapping between Java type and {@code ValueStructure} code list is as below:
167     *
168     * <table class="ogc">
169     *   <caption>Mapping from Java type to {@code ValueStructure}</caption>
170     *   <tr><th>Java or GeoAPI type</th>                              <th>Code list value</th></tr>
171     *   <tr><td>{@link java.util.Collection}</td>                     <td>{@link #BAG}</td></tr>
172     *   <tr><td>{@link java.util.Set}</td>                            <td>{@link #SET}</td></tr>
173     *   <tr><td>{@link java.util.List}</td>                           <td>{@link #SEQUENCE}</td></tr>
174     *   <tr><td>{@link java.util.Map}</td>                            <td>{@link #TABLE}</td></tr>
175     *   <tr><td>{@link org.opengis.referencing.operation.Matrix}</td> <td>{@link #MATRIX}</td></tr>
176     * </table>
177     *
178     * @param  type  the Java type for which to get a structure, or {@code null} if unknown.
179     * @return structure for the given type, or an empty value if there is no value for the given type.
180     */
181    public static Optional<ValueStructure> valueOf(final Class<?> type) {
182        if (type != null) {
183            for (final ValueStructure value : PREDEFINED) {
184                if (value.type.isAssignableFrom(type)) {
185                    return Optional.of(value);
186                }
187            }
188        }
189        return Optional.empty();
190    }
191
192    /**
193     * Returns the Java type corresponding to this code list value.
194     * The Java type is documented in each code list value.
195     *
196     * @departure integration
197     *   Added for integration with the Java language.
198     *
199     * @return the Java type for this code list value.
200     */
201    public Optional<Class<?>> toJavaType() {
202        return Optional.ofNullable(type);
203    }
204}