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