001/*
002 *    GeoAPI - Java interfaces for OGC/ISO standards
003 *    Copyright © 2008-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.referencing;
019
020import java.util.Set;
021import java.util.List;
022
023import org.opengis.parameter.*;
024import org.opengis.test.ValidatorContainer;
025import static org.junit.jupiter.api.Assertions.*;
026import static org.opengis.test.Assertions.assertBetween;
027import static org.opengis.test.Assertions.assertPositive;
028import static org.opengis.test.Assertions.assertContains;
029import static org.opengis.test.Assertions.assertValidRange;
030
031
032/**
033 * Validates {@link ParameterValue} and related objects from the {@code org.opengis.parameter}
034 * package.
035 *
036 * <p>This class is provided for users wanting to override the validation methods. When the default
037 * behavior is sufficient, the {@link org.opengis.test.Validators} static methods provide a more
038 * convenient way to validate various kinds of objects.</p>
039 *
040 * @author  Martin Desruisseaux (Geomatys)
041 * @version 3.1
042 * @since   2.2
043 */
044public class ParameterValidator extends ReferencingValidator {
045    /**
046     * Creates a new validator instance.
047     *
048     * @param container  the set of validators to use for validating other kinds of objects
049     *                   (see {@linkplain #container field javadoc}).
050     */
051    public ParameterValidator(final ValidatorContainer container) {
052        super(container, "org.opengis.parameter");
053    }
054
055    /**
056     * For each interface implemented by the given object, invokes the corresponding
057     * {@code validate(…)} method defined in this class (if any).
058     *
059     * @param  object  the object to dispatch to {@code validate(…)} methods, or {@code null}.
060     * @return number of {@code validate(…)} methods invoked in this class for the given object.
061     */
062    public int dispatch(final GeneralParameterDescriptor object) {
063        int n = 0;
064        if (object != null) {
065            if (object instanceof ParameterDescriptor<?>)   {validate((ParameterDescriptor<?>)   object); n++;}
066            if (object instanceof ParameterDescriptorGroup) {validate((ParameterDescriptorGroup) object); n++;}
067            if (n == 0) {
068                validateIdentifiedObject(object);
069            }
070        }
071        return n;
072    }
073
074    /**
075     * For each interface implemented by the given object, invokes the corresponding
076     * {@code validate(…)} method defined in this class (if any).
077     *
078     * @param  object  the object to dispatch to {@code validate(…)} methods, or {@code null}.
079     * @return number of {@code validate(…)} methods invoked in this class for the given object.
080     */
081    public int dispatch(final GeneralParameterValue object) {
082        int n = 0;
083        if (object != null) {
084            if (object instanceof ParameterValue<?>)   {validate((ParameterValue<?>)   object); n++;}
085            if (object instanceof ParameterValueGroup) {validate((ParameterValueGroup) object); n++;}
086            if (n == 0) {
087                dispatch(object.getDescriptor());
088            }
089        }
090        return n;
091    }
092
093    /**
094     * Validates the given descriptor.
095     *
096     * @param  <T>     the class of parameter values.
097     * @param  object  the object to validate, or {@code null}.
098     */
099    public <T> void validate(final ParameterDescriptor<T> object) {
100        if (object == null) {
101            return;
102        }
103        validateIdentifiedObject(object);
104        final Class<T> valueClass = object.getValueClass();
105        mandatory(valueClass, "ParameterDescriptor: getValueClass() cannot return null.");
106        Set<T> validValues = object.getValidValues();
107        if (validValues != null) {
108            validate(validValues);
109            for (final T value : validValues) {
110                if (value != null) {
111                    assertInstanceOf(valueClass, value, "ParameterDescriptor: getValidValues() has unexpected element.");
112                }
113            }
114        }
115        final Comparable<T> min = object.getMinimumValue();
116        if (min != null) {
117            assertInstanceOf(valueClass, min, "ParameterDescriptor: getMinimumValue() returns unexpected value.");
118        }
119        final Comparable<T> max = object.getMaximumValue();
120        if (max != null) {
121            assertInstanceOf(valueClass, max, "ParameterDescriptor: getMaximumValue() returns unexpected value.");
122        }
123        assertValidRange(min, max, "ParameterDescriptor: inconsistent minimum and maximum values.");
124        final T def = object.getDefaultValue();
125        if (def != null) {
126            assertInstanceOf(valueClass, def, "ParameterDescriptor: getDefaultValue() returns unexpected value.");
127            assertBetween(min, max, def, "ParameterDescriptor: getDefaultValue() out of range.");
128        }
129        assertBetween(0, 1, object.getMinimumOccurs(), "ParameterDescriptor: getMinimumOccurs() shall returns 0 or 1.");
130        assertEquals(1, object.getMaximumOccurs(), "ParameterDescriptor: getMaximumOccurs() shall returns exactly 1.");
131    }
132
133    /**
134     * Validates the given descriptor.
135     *
136     * @param  object  the object to validate, or {@code null}.
137     */
138    public void validate(final ParameterDescriptorGroup object) {
139        if (object == null) {
140            return;
141        }
142        validateIdentifiedObject(object);
143        final List<GeneralParameterDescriptor> descriptors = object.descriptors();
144        if (requireMandatoryAttributes) {
145            // Do not invoke mandatory(…) because we allow empty collections.
146            assertNotNull(descriptors, "ParameterDescriptorGroup: descriptors() should not return null.");
147        }
148        if (descriptors != null) {
149            validate(descriptors);
150            for (final GeneralParameterDescriptor descriptor : descriptors) {
151                assertNotNull(descriptor, "ParameterDescriptorGroup: descriptors() cannot contain null element.");
152                dispatch(descriptor);
153                final GeneralParameterDescriptor byName = object.descriptor(descriptor.getName().getCode());
154                mandatory(byName, "ParameterDescriptorGroup: descriptor(String) should returns a value.");
155                if (byName != null) {
156                    assertEquals(descriptor, byName, "ParameterDescriptorGroup: descriptor(String) inconsistent with descriptors().");
157                }
158            }
159        }
160        final int minOccurs = object.getMinimumOccurs();
161        assertPositive(minOccurs, "ParameterDescriptor: getMinimumOccurs() cannot be negative.");
162        assertValidRange(minOccurs, object.getMaximumOccurs(),
163                "ParameterDescriptor: getMaximumOccurs() gives inconsistent range.");
164    }
165
166    /**
167     * Validates the given parameter value.
168     *
169     * @param  <T>     the class of parameter values.
170     * @param  object  the object to validate, or {@code null}.
171     */
172    public <T> void validate(final ParameterValue<T> object) {
173        if (object == null) {
174            return;
175        }
176        final ParameterDescriptor<T> descriptor = object.getDescriptor();
177        mandatory(descriptor, "ParameterValue: shall have a descriptor.");
178        validate(descriptor);
179        final T value = object.getValue();
180        if (value != null) {
181            if (descriptor != null) {
182                final Class<T> valueClass = descriptor.getValueClass();
183                assertInstanceOf(valueClass, value, "ParameterValue: getValue() returns unexpected value.");
184                final Set<T> validValues = descriptor.getValidValues();
185                if (validValues != null) {
186                    validate(validValues);
187                    assertContains(validValues, value, "ParameterValue: getValue() not a member of getValidValues() set.");
188                }
189                assertBetween(descriptor.getMinimumValue(), descriptor.getMaximumValue(), value,
190                        "ParameterValue: getValue() is out of bounds.");
191            }
192        }
193    }
194
195    /**
196     * Validates the given coordinate system.
197     *
198     * @param  object  the object to validate, or {@code null}.
199     */
200    public void validate(final ParameterValueGroup object) {
201        if (object == null) {
202            return;
203        }
204        final ParameterDescriptorGroup descriptors = object.getDescriptor();
205        mandatory(descriptors, "ParameterValueGroup: shall have a descriptor.");
206        validate(descriptors);
207        final List<GeneralParameterValue> values = object.values();
208        if (requireMandatoryAttributes) {
209            // Do not invoke mandatory(…) because we allow empty collections.
210            assertNotNull(values, "ParameterValueGroup: values() should not return null.");
211        }
212        if (values == null) {
213            return;
214        }
215        validate(values);
216        for (final GeneralParameterValue value : values) {
217            assertNotNull(value, "ParameterValueGroup: values() cannot contain null element.");
218            dispatch(value);
219            final GeneralParameterDescriptor descriptor = value.getDescriptor();
220            mandatory(descriptor, "GeneralParameterValue: expected a descriptor.");
221            if (descriptor == null) {
222                continue;
223            }
224            final String name = descriptor.getName().getCode();
225            mandatory(name, "GeneralParameterDescriptor: expected a name.");
226            if (name == null) {
227                continue;
228            }
229            if (descriptors != null) {
230                final GeneralParameterDescriptor byName = descriptors.descriptor(name);
231                mandatory(byName, "ParameterDescriptorGroup: should never return null.");
232                if (byName != null) {
233                    assertEquals(descriptor, byName,
234                            "ParameterValueGroup: descriptor(String) inconsistent with value.getDescriptor().");
235                }
236            }
237            if (value instanceof ParameterValue<?>) {
238                final ParameterValue<?> byName = object.parameter(name);
239                mandatory(byName, "ParameterValueGroup: parameter(String) should returns a value.");
240                if (byName != null) {
241                    assertEquals(value, byName, "ParameterValueGroup: value(String) inconsistent with values().");
242                }
243            }
244        }
245    }
246}