001/*
002 *    GeoAPI - Java interfaces for OGC/ISO standards
003 *    Copyright © 2011-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.test;
019
020import java.util.Map;
021import java.util.Collections;
022import java.util.LinkedHashMap;
023import java.util.Objects;
024import java.io.Serializable;
025
026import org.opengis.util.CodeList;
027import org.opengis.util.GenericName;
028import org.opengis.util.InternationalString;
029import org.opengis.geometry.DirectPosition;
030import org.opengis.referencing.IdentifiedObject;
031import org.opengis.referencing.cs.CSFactory;
032import org.opengis.referencing.cs.CSAuthorityFactory;
033import org.opengis.referencing.crs.CRSFactory;
034import org.opengis.referencing.crs.CRSAuthorityFactory;
035import org.opengis.referencing.datum.DatumFactory;
036import org.opengis.referencing.datum.DatumAuthorityFactory;
037import org.opengis.referencing.operation.Matrix;
038import org.opengis.referencing.operation.MathTransform;
039import org.opengis.referencing.operation.MathTransformFactory;
040import org.opengis.referencing.operation.CoordinateOperationFactory;
041import org.opengis.referencing.operation.CoordinateOperationAuthorityFactory;
042
043
044/**
045 * Contains information about the test environment, like available factories and disabled tests.
046 * {@code Configuration} is used:
047 *
048 * <ul>
049 *   <li>Before each test is executed.
050 *       For example, an implementation can declare that it does not support the calculation of transform derivative.</li>
051 *   <li>After each test is executed, for obtaining the actual configuration used by the test.</li>
052 * </ul>
053 *
054 * This class provides {@link #get get}, {@link #put put} and {@link #remove remove} methods
055 * similar to those of the {@code java.util.Map} interface, with the addition of type-safety.
056 * The predefined keys are listed below:
057 *
058 * <table class="ogc" style="td {vertical-align:top}">
059 * <caption>Configuration properties</caption>
060 * <tr>
061 *   <th>Supported features</th>
062 *   <th>Factories</th>
063 *   <th>Other</th>
064 * </tr>
065 * <tr><td>
066 * {@link Key#isMultiLocaleSupported              isMultiLocaleSupported}<br>
067 * {@link Key#isMixedNameSyntaxSupported          isMixedNameSyntaxSupported}<br>
068 * {@link Key#isStandardNameSupported             isStandardNameSupported}<br>
069 * {@link Key#isStandardAliasSupported            isStandardAliasSupported}<br>
070 * {@link Key#isDependencyIdentificationSupported isDependencyIdentificationSupported}<br>
071 * {@link Key#isDoubleToDoubleSupported           isDoubleToDoubleSupported}<br>
072 * {@link Key#isFloatToFloatSupported             isFloatToFloatSupported}<br>
073 * {@link Key#isDoubleToFloatSupported            isDoubleToFloatSupported}<br>
074 * {@link Key#isFloatToDoubleSupported            isFloatToDoubleSupported}<br>
075 * {@link Key#isOverlappingArraySupported         isOverlappingArraySupported}<br>
076 * {@link Key#isInverseTransformSupported         isInverseTransformSupported}<br>
077 * {@link Key#isDerivativeSupported               isDerivativeSupported}<br>
078 * {@link Key#isNonSquareMatrixSupported          isNonSquareMatrixSupported}<br>
079 * {@link Key#isNonBidimensionalSpaceSupported    isNonBidimensionalSpaceSupported}<br>
080 * {@link Key#isAxisSwappingSupported             isAxisSwappingSupported}</td><td>
081 * {@link Key#mtFactory                           mtFactory}<br>
082 * {@link Key#copFactory                          copFactory}<br>
083 * {@link Key#copAuthorityFactory                 copAuthorityFactory}<br>
084 * {@link Key#crsFactory                          crsFactory}<br>
085 * {@link Key#crsAuthorityFactory                 crsAuthorityFactory}<br>
086 * {@link Key#csFactory                           csFactory}<br>
087 * {@link Key#csAuthorityFactory                  csAuthorityFactory}<br>
088 * {@link Key#datumFactory                        datumFactory}<br>
089 * {@link Key#datumAuthorityFactory               datumAuthorityFactory}<br>
090 * {@link Key#isFactoryPreservingUserValues       isFactoryPreservingUserValues}</td><td>
091 * {@link Key#validators                          validators}<br>
092 * {@link Key#isValidationEnabled                 isValidationEnabled}<br>
093 * {@link Key#isToleranceRelaxed                  isToleranceRelaxed}
094 * </td></tr></table>
095 *
096 * @see TestCase#configuration()
097 *
098 * @author  Martin Desruisseaux (Geomatys)
099 * @version 3.1
100 * @since   3.1
101 */
102public class Configuration implements Serializable {
103    /**
104     * For cross-version compatibility.
105     */
106    private static final long serialVersionUID = 4725836424438658750L;
107
108    /**
109     * The map were to store the configuration entries.
110     */
111    private final LinkedHashMap<Key<?>,Object> properties;
112
113    /**
114     * An unmodifiable view of the {@link #properties} map.
115     *
116     * @see #map()
117     */
118    @SuppressWarnings("serial")     // Okay because wrapping a serializable map.
119    private final Map<Key<?>,Object> unmodifiable;
120
121    /**
122     * Creates a new, initially empty, configuration map.
123     */
124    public Configuration() {
125        properties = new LinkedHashMap<>();
126        unmodifiable = Collections.unmodifiableMap(properties);
127    }
128
129    /**
130     * Creates a new configuration with the same mappings as the specified configuration.
131     *
132     * @param  toCopy  the configuration whose mappings are to be placed in this map.
133     * @throws NullPointerException if the specified configuration is null.
134     */
135    public Configuration(final Configuration toCopy) {
136        properties = new LinkedHashMap<>(toCopy.properties);
137        unmodifiable = Collections.unmodifiableMap(properties);
138    }
139
140    /**
141     * Returns the value to which the specified key is mapped, or {@code null}
142     * if this map contains no mapping for the key.
143     *
144     * @param  <T>  the value type, which is determined by the key.
145     * @param  key  the key whose associated value is to be returned.
146     * @return the value to which the specified key is mapped, or {@code null}
147     *         if this map contains no mapping for the key.
148     * @throws NullPointerException if the specified key is null.
149     */
150    public <T> T get(final Key<T> key) {
151        return key.type.cast(properties.get(key));
152    }
153
154    /**
155     * Removes the mapping for a key from this map if it is present.
156     *
157     * @param  <T>  the value type, which is determined by the key.
158     * @param  key  the key whose associated value is to be removed.
159     * @return the value which was previously mapped to the specified key, or {@code null}.
160     * @throws NullPointerException if the specified key is null.
161     */
162    public <T> T remove(final Key<T> key) {
163        return key.type.cast(properties.remove(key));
164    }
165
166    /**
167     * Associates the specified value with the specified key in this map.
168     *
169     * @param  <T>    the value type, which is determined by the key.
170     * @param  key    the key with which the specified value is to be associated.
171     * @param  value  the value to be associated with the specified key (can be {@code null}).
172     * @return the previous value associated with {@code key}, or {@code null} if there was no mapping for that key.
173     * @throws NullPointerException if the specified key is null.
174     */
175    public <T> T put(final Key<T> key, final T value) {
176        return key.type.cast(properties.put(key, value));
177    }
178
179    /**
180     * Declares that all given operations are unsupported. This is a convenience method
181     * invoking <code>{@linkplain #put(Key,Object) put}(key, Boolean.False)</code> for
182     * all operations given in argument.
183     *
184     * @param  operations  the operations to declare as unsupported.
185     * @throws NullPointerException if a specified key is null.
186     */
187    @SafeVarargs
188    public final void unsupported(final Key<Boolean>... operations) {
189        for (final Key<Boolean> operation : operations) {
190            put(operation, Boolean.FALSE);
191        }
192    }
193
194    /**
195     * Returns all entries as an unmodifiable map.
196     *
197     * @return a map view over the entries in this {@code Configuration} object.
198     */
199    @SuppressWarnings("ReturnOfCollectionOrArrayField")
200    public Map<Key<?>,Object> map() {
201        return unmodifiable;
202    }
203
204    /**
205     * Returns a hash code value for this configuration map.
206     */
207    @Override
208    public int hashCode() {
209        return properties.hashCode() ^ (int) serialVersionUID;
210    }
211
212    /**
213     * Compares this configuration with the given object for equality.
214     *
215     * @param  other  the other object to compare with this configuration.
216     */
217    @Override
218    public boolean equals(final Object other) {
219        if (other instanceof Configuration) {
220            return properties.equals(((Configuration) other).properties);
221        }
222        return false;
223    }
224
225    /**
226     * Returns a string representation of this configuration map.
227     */
228    @Override
229    public String toString() {
230        return properties.toString();
231    }
232
233    /**
234     * Type-safe keys that can be used in a {@link Configuration} map.
235     * This code list is extensible: users can create new instances by
236     * invoking the {@link #valueOf(String, Class)} static method.
237     *
238     * <h2>Note on field names</h2>
239     * Every constants declared in this class have a name matching exactly the field names in
240     * {@link TestCase} subclasses. This is a departure from the usual <q>all upper-case letters</q> convention,
241     * but make the relationship with fields more obvious and the parsing of {@link java.util.Properties} files easier.
242     *
243     * @param  <T>  the type of values associated with the key.
244     *
245     * @author  Martin Desruisseaux (Geomatys)
246     * @version 3.1
247     * @since   3.1
248     */
249    public static final class Key<T> extends CodeList<Key<?>> {
250        /**
251         * For cross-version compatibility.
252         */
253        private static final long serialVersionUID = -5920183652024058448L;
254
255        /*
256         * If new constants are added, please remember to update the Configuration class javadoc.
257         */
258
259        /**
260         * Whether the {@link InternationalString} instances can support more than one {@link java.util.Locale}.
261         * If {@code false}, then the factory method may retain only one locale among the set of user-provided
262         * localized strings.
263         *
264         * @see org.opengis.test.util.NameTest#isMultiLocaleSupported
265         */
266        public static final Key<Boolean> isMultiLocaleSupported =
267                new Key<>(Boolean.class, "isMultiLocaleSupported");
268
269        /**
270         * Whether the {@link GenericName} instances can apply different syntax rules in different
271         * parts of their name. If {@code true}, then URI using different separators in different
272         * parts of their name (e.g. {@code ":"}, {@code "."}, {@code "/"} and {@code "#"}
273         * in {@code "http://www.opengis.net/gml/srs/epsg.xml#4326"}) are supported.
274         * If {@code false}, then only a single rule can be applied to the name as a whole
275         * (e.g. only the {@code ":"} separator is used in {@code "urn:ogc:def:crs:epsg:4326"}).
276         *
277         * @see org.opengis.test.util.NameTest#isMixedNameSyntaxSupported
278         */
279        public static final Key<Boolean> isMixedNameSyntaxSupported =
280                new Key<>(Boolean.class, "isMixedNameSyntaxSupported");
281
282        /**
283         * Whether the {@link IdentifiedObject} instances have {@linkplain IdentifiedObject#getName()
284         * names} matching the names declared in the EPSG database.
285         */
286        public static final Key<Boolean> isStandardNameSupported =
287                new Key<>(Boolean.class, "isStandardNameSupported");
288
289        /**
290         * Whether the {@link IdentifiedObject} instances have at least the
291         * {@linkplain IdentifiedObject#getAlias() aliases} declared in the EPSG database.
292         */
293        public static final Key<Boolean> isStandardAliasSupported =
294                new Key<>(Boolean.class, "isStandardAliasSupported");
295
296        /**
297         * Whether the {@link IdentifiedObject} instances created indirectly by the factories
298         * are expected to have correct identification information.
299         */
300        public static final Key<Boolean> isDependencyIdentificationSupported =
301                new Key<>(Boolean.class, "isDependencyIdentificationSupported");
302
303        /**
304         * Whether the authority factory supports creation of deprecated {@link IdentifiedObject} instances.
305         */
306        public static final Key<Boolean> isDeprecatedObjectCreationSupported =
307                new Key<>(Boolean.class, "isDeprecatedObjectCreationSupported");
308
309        /**
310         * Whether {@link MathTransform#transform(double[], int, double[], int, int)} is supported.
311         * Implementers can set the value for this key to {@code false} in order to test
312         * {@link MathTransform} instances which are not yet fully implemented.
313         *
314         * @see org.opengis.test.referencing.TransformTestCase#isDoubleToDoubleSupported
315         */
316        public static final Key<Boolean> isDoubleToDoubleSupported =
317                new Key<>(Boolean.class, "isDoubleToDoubleSupported");
318
319        /**
320         * Whether {@link MathTransform#transform(float[], int, float[], int, int)} is supported.
321         * Implementers can set the value for this key to {@code false} in order to test
322         * {@link MathTransform} instances which are not yet fully implemented.
323         *
324         * @see org.opengis.test.referencing.TransformTestCase#isFloatToFloatSupported
325         */
326        public static final Key<Boolean> isFloatToFloatSupported =
327                new Key<>(Boolean.class, "isFloatToFloatSupported");
328
329        /**
330         * Whether {@link MathTransform#transform(double[], int, float[], int, int)} is supported.
331         * Implementers can set the value for this key to {@code false} in order to test
332         * {@link MathTransform} instances which are not yet fully implemented.
333         *
334         * @see org.opengis.test.referencing.TransformTestCase#isDoubleToFloatSupported
335         */
336        public static final Key<Boolean> isDoubleToFloatSupported =
337                new Key<>(Boolean.class, "isDoubleToFloatSupported");
338
339        /**
340         * Whether {@link MathTransform#transform(float[], int, double[], int, int)} is supported.
341         * Implementers can set the value for this key to {@code false} in order to test
342         * {@link MathTransform} instances which are not yet fully implemented.
343         *
344         * @see org.opengis.test.referencing.TransformTestCase#isFloatToDoubleSupported
345         */
346        public static final Key<Boolean> isFloatToDoubleSupported =
347                new Key<>(Boolean.class, "isFloatToDoubleSupported");
348
349        /**
350         * Whether source and destination arrays can overlap in {@link MathTransform} operations.
351         * Overlapping occur when:
352         *
353         * <ul>
354         *   <li>The invoked method is one of the following:
355         *     <ul>
356         *       <li>{@link MathTransform#transform(double[], int, double[], int, int)}</li>
357         *       <li>{@link MathTransform#transform(float[], int, float[], int, int)}</li>
358         *     </ul></li>
359         *   <li>The {@code srcPts} and {@code dstPts} arguments are references to the same array.</li>
360         *   <li>The {@code srcOff} and {@code dstOff} offsets are such that the source region of
361         *       the array overlaps with the target region.</li>
362         * </ul>
363         *
364         * @see org.opengis.test.referencing.TransformTestCase#isOverlappingArraySupported
365         */
366        public static final Key<Boolean> isOverlappingArraySupported =
367                new Key<>(Boolean.class, "isOverlappingArraySupported");
368
369        /**
370         * Whether {@link MathTransform#inverse()} is supported.
371         * Implementers can set the value for this key to {@code false} in order to test
372         * {@link MathTransform} instances which are not yet fully implemented.
373         *
374         * @see org.opengis.test.referencing.TransformTestCase#isInverseTransformSupported
375         */
376        public static final Key<Boolean> isInverseTransformSupported =
377                new Key<>(Boolean.class, "isInverseTransformSupported");
378
379        /**
380         * Whether {@link MathTransform#derivative(DirectPosition)} is supported.
381         * Implementers can set the value for this key to {@code false} in order to test
382         * {@link MathTransform} instances which are not yet fully implemented.
383         *
384         * @see org.opengis.test.referencing.TransformTestCase#isDerivativeSupported
385         */
386        public static final Key<Boolean> isDerivativeSupported =
387                new Key<>(Boolean.class, "isDerivativeSupported");
388
389        /**
390         * Whether {@link MathTransformFactory#createAffineTransform(Matrix)} accepts non-square matrixes.
391         *
392         * @see org.opengis.test.referencing.AffineTransformTest#isNonSquareMatrixSupported
393         */
394        public static final Key<Boolean> isNonSquareMatrixSupported =
395                new Key<>(Boolean.class, "isNonSquareMatrixSupported");
396
397        /**
398         * Whether {@link MathTransformFactory} can create transforms between spaces that are
399         * not two-dimensional. If {@code true}, then the tested spaces may be one-dimensional
400         * (typically elevation or time), three-dimensional or four-dimensional.
401         *
402         * @see org.opengis.test.referencing.AffineTransformTest#isNonBidimensionalSpaceSupported
403         */
404        public static final Key<Boolean> isNonBidimensionalSpaceSupported =
405                new Key<>(Boolean.class, "isNonBidimensionalSpaceSupported");
406
407        /**
408         * Whether (<var>y</var>,<var>x</var>) axis order is supported. This axis swapping is not
409         * supported, then the tests that would normally expect (<var>y</var>,<var>x</var>) axis
410         * order or <i>South Oriented</i> CRS will rather use the (<var>x</var>,<var>y</var>)
411         * axis order and <i>North Oriented</i> CRS in their test.
412         *
413         * @see org.opengis.test.referencing.AuthorityFactoryTest#isAxisSwappingSupported
414         */
415        public static final Key<Boolean> isAxisSwappingSupported =
416                new Key<>(Boolean.class, "isAxisSwappingSupported");
417
418        /**
419         * Whether the test methods can invoke a <code>{@linkplain TestCase#validators validators}.validate(…)}</code>
420         * method. GeoAPI allows to disable the validation checks in some tests where strict conformance to a standard
421         * is relaxed.
422         *
423         * <div class="note"><b>Example:</b>
424         * ISO 19111 (the <cite>Referencing by Coordinates</cite> abstract model) specifies that the name of
425         * the latitude axis in a geographic CRS shall be <q>Geodetic latitude</q> while ISO 19162
426         * (a.k.a <cite>Well Known Text 2</cite>) specifies <q>Latitude</q>. Consequently, the GeoAPI
427         * conformance module allows implementer to disable the check for ISO 19111 conformance if their WKT
428         * parser does not adapt the parsed CRS objects to the ISO 19111 axis naming.</div>
429         *
430         * @see org.opengis.test.referencing.WKTParserTest#isValidationEnabled
431         */
432        public static final Key<Boolean> isValidationEnabled =
433                new Key<>(Boolean.class, "isValidationEnabled");
434
435        /**
436         * Whether the tolerance threshold of a {@link org.opengis.test.referencing.TransformTestCase}
437         * has been relaxed. This information is determined after test execution.
438         */
439        public static final Key<Boolean> isToleranceRelaxed =
440                new Key<>(Boolean.class, "isToleranceRelaxed");
441
442        /**
443         * The provider of {@linkplain Units units} to use for tests. If this configuration hint
444         * is not specified, then the {@linkplain Units#getDefault() default instance} is used.
445         */
446        public static final Key<Units> units = new Key<>(Units.class, "units");
447
448        /**
449         * The {@linkplain MathTransformFactory Math Transform factory} instance used for a test.
450         *
451         * @see org.opengis.test.referencing.AffineTransformTest#mtFactory
452         * @see org.opengis.test.referencing.ParameterizedTransformTest#mtFactory
453         * @see org.opengis.test.referencing.PseudoEpsgFactory#mtFactory
454         */
455        public static final Key<MathTransformFactory> mtFactory =
456                new Key<>(MathTransformFactory.class, "mtFactory");
457
458        /**
459         * The {@linkplain CoordinateOperationFactory Coordinate Operation factory} instance used for a test.
460         *
461         * @see org.opengis.test.referencing.PseudoEpsgFactory#copFactory
462         */
463        public static final Key<CoordinateOperationFactory> copFactory =
464                new Key<>(CoordinateOperationFactory.class, "copFactory");
465
466        /**
467         * The {@linkplain CoordinateOperationAuthorityFactory Coordinate Operation authority factory}
468         * instance used for a test.
469         */
470        public static final Key<CoordinateOperationAuthorityFactory> copAuthorityFactory =
471                new Key<>(CoordinateOperationAuthorityFactory.class, "copAuthorityFactory");
472
473        /**
474         * The {@linkplain CRSFactory Coordinate Reference System factory} instance used for a test.
475         *
476         * @see org.opengis.test.referencing.ObjectFactoryTest#crsFactory
477         * @see org.opengis.test.referencing.PseudoEpsgFactory#crsFactory
478         */
479        public static final Key<CRSFactory> crsFactory =
480                new Key<>(CRSFactory.class, "crsFactory");
481
482        /**
483         * The {@linkplain CRSAuthorityFactory Coordinate Reference System authority factory}
484         * instance used for a test.
485         *
486         * @see org.opengis.test.referencing.AuthorityFactoryTest#crsAuthorityFactory
487         */
488        public static final Key<CRSAuthorityFactory> crsAuthorityFactory =
489                new Key<>(CRSAuthorityFactory.class, "crsAuthorityFactory");
490
491        /**
492         * The {@linkplain CSFactory Coordinate System factory} instance used for a test.
493         *
494         * @see org.opengis.test.referencing.ObjectFactoryTest#csFactory
495         * @see org.opengis.test.referencing.PseudoEpsgFactory#csFactory
496         */
497        public static final Key<CSFactory> csFactory =
498                new Key<>(CSFactory.class, "csFactory");
499
500        /**
501         * The {@linkplain CSAuthorityFactory Coordinate System authority factory} instance used for a test.
502         *
503         * @see org.opengis.test.referencing.AuthorityFactoryTest#csAuthorityFactory
504         */
505        public static final Key<CSAuthorityFactory> csAuthorityFactory =
506                new Key<>(CSAuthorityFactory.class, "csAuthorityFactory");
507
508        /**
509         * The {@linkplain DatumFactory Datum factory} instance used for a test.
510         *
511         * @see org.opengis.test.referencing.ObjectFactoryTest#datumFactory
512         * @see org.opengis.test.referencing.PseudoEpsgFactory#datumFactory
513         */
514        public static final Key<DatumFactory> datumFactory =
515                new Key<>(DatumFactory.class, "datumFactory");
516
517        /**
518         * The {@linkplain DatumAuthorityFactory Datum authority factory} instance used for a test.
519         *
520         * @see org.opengis.test.referencing.AuthorityFactoryTest#datumAuthorityFactory
521         */
522        public static final Key<DatumAuthorityFactory> datumAuthorityFactory =
523                new Key<>(DatumAuthorityFactory.class, "datumAuthorityFactory");
524
525        /**
526         * Whether the objects created by the tested {@link org.opengis.referencing.ObjectFactory} use the
527         * specified values <i>as-is</i>. This flag should be set to {@code false} if the factory performs
528         * any of the following operations:
529         *
530         * <ul>
531         *   <li>Convert numerical values from user-provided linear units to metres.</li>
532         *   <li>Convert numerical values from user-provided angular units to degrees.</li>
533         *   <li>Change ellipsoid second defining parameter
534         *       (e.g. from <i>semi-major axis length</i> to an equivalent <i>inverse flattening factor</i>).</li>
535         *   <li>Change map projection parameters
536         *       (e.g. from <i>standard parallel</i> to an equivalent <i>scale factor</i>).</li>
537         *   <li>Any other change that preserve numeric equivalence.</li>
538         * </ul>
539         *
540         * If the factory does not perform any of the above conversions, then this flag can be {@code true}.
541         */
542        public static final Key<Boolean> isFactoryPreservingUserValues =
543                new Key<>(Boolean.class, "isFactoryPreservingUserValues");
544
545        /**
546         * The set of {@link Validator} instances to use for validating objects.
547         * If no value is provided for this key, then the system-wide
548         * {@linkplain Validators#DEFAULT default validators} are used.
549         *
550         * @see Validators#DEFAULT
551         */
552        public static final Key<ValidatorContainer> validators =
553                new Key<>(ValidatorContainer.class, "validators");
554
555        /**
556         * The type of values associated to this key.
557         */
558        final Class<T> type;
559
560        /**
561         * Constructs a key with the given name.
562         *
563         * @param  type  the type of values associated to the new key.
564         * @param  name  the key name. This name must not be in use by any other key.
565         */
566        private Key(final Class<T> type, final String name) {
567            super(name);
568            this.type = type;
569        }
570
571        /**
572         * Returns the key that matches the given name, or returns a new one if none match it.
573         * If no existing instance is found, then a new one is created for the given name and
574         * type.
575         *
576         * @param  <T>   the type of the key to fetch.
577         * @param  type  the type of the key to fetch.
578         * @param  name  the name of the key to fetch or to create.
579         * @return a key matching the given name.
580         * @throws NullPointerException if the given name or type is {@code null}.
581         * @throws ClassCastException if a key is found but the type is not assignable to the given type.
582         */
583        @SuppressWarnings("unchecked")
584        public static <T> Key<? extends T> valueOf(final String name, final Class<T> type) {
585            Objects.requireNonNull(type, "type");
586            @SuppressWarnings("rawtypes")
587            final Key<?> key = (Key<?>) valueOf(Key.class, name, (n) -> new Key(type, n)).get();
588            if (type.isAssignableFrom(key.type)) {
589                return (Key<? extends T>) key;
590            }
591            throw new ClassCastException(key.type.getCanonicalName());
592        }
593
594        /**
595         * Returns the list of {@code Key}s.
596         *
597         * @return the list of keys declared in the current JVM.
598         */
599        @SuppressWarnings("unchecked")
600        public static Key<?>[] values() {
601            return values(Key.class);
602        }
603
604        /**
605         * Returns the list of codes of the same kind as this code list element.
606         * Invoking this method is equivalent to invoking {@link #values()}, except that
607         * this method can be invoked on an instance of the parent {@code CodeList} class.
608         *
609         * @return all code {@linkplain #values() values} for this code list.
610         */
611        @Override
612        public Key<?>[] family() {
613            return values();
614        }
615
616        /**
617         * Returns the type of values assigned to this key.
618         *
619         * @return the value type.
620         */
621        public Class<T> valueType() {
622            return type;
623        }
624    }
625}