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