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.metadata;
019
020import org.opengis.util.Record;
021import org.opengis.metadata.citation.Citation;
022import org.opengis.metadata.content.RangeDimension;
023import org.opengis.metadata.quality.*;
024import org.opengis.metadata.maintenance.Scope;
025import org.opengis.test.ValidatorContainer;
026
027import static org.junit.jupiter.api.Assertions.*;
028
029
030/**
031 * Validates {@link DataQuality} and related objects from the {@code org.opengis.metadata.quality} package.
032 *
033 * <p>This class is provided for users wanting to override the validation methods.
034 * When the default behavior is sufficient, the {@link org.opengis.test.Validators}
035 * static methods provide a more convenient way to validate various kinds of objects.</p>
036 *
037 * @author  Martin Desruisseaux (Geomatys)
038 * @version 3.1
039 * @since   3.1
040 */
041public class QualityValidator extends MetadataValidator {
042    /**
043     * Creates a new validator instance.
044     *
045     * @param container  the set of validators to use for validating other kinds of objects
046     *                   (see {@linkplain #container field javadoc}).
047     */
048    public QualityValidator(final ValidatorContainer container) {
049        super(container, "org.opengis.metadata.quality");
050    }
051
052    /**
053     * For each interface implemented by the given object, invokes the corresponding
054     * {@code validate(…)} method defined in this class (if any).
055     *
056     * @param  object  the object to dispatch to {@code validate(…)} methods, or {@code null}.
057     * @return number of {@code validate(…)} methods invoked in this class for the given object.
058     */
059    public int dispatch(final Element object) {
060        int n = 0;
061        if (object != null) {
062            if (object instanceof PositionalAccuracy) {validate((PositionalAccuracy) object); n++;}
063            if (n == 0) {
064                validateElement(object);
065            }
066        }
067        return n;
068    }
069
070    /**
071     * For each interface implemented by the given object, invokes the corresponding
072     * {@code validate(…)} method defined in this class (if any).
073     *
074     * @param  object  the object to dispatch to {@code validate(…)} methods, or {@code null}.
075     * @return number of {@code validate(…)} methods invoked in this class for the given object.
076     */
077    public int dispatch(final Result object) {
078        int n = 0;
079        if (object != null) {
080            if (object instanceof DescriptiveResult)  {validate((DescriptiveResult)  object); n++;}
081            if (object instanceof ConformanceResult)  {validate((ConformanceResult)  object); n++;}
082            if (object instanceof QuantitativeResult) {validate((QuantitativeResult) object); n++;}
083            if (object instanceof CoverageResult)     {validate((CoverageResult)     object); n++;}
084            if (n == 0) {
085                validateResult(object);
086            }
087        }
088        return n;
089    }
090
091    /**
092     * Validates the data quality.
093     *
094     * @param  object  the object to validate, or {@code null}.
095     */
096    public void validate(final DataQuality object) {
097        if (object == null) {
098            return;
099        }
100        final Scope scope = object.getScope();
101        mandatory(scope, "DataQuality: must have a scope.");
102        container.validate(scope);
103        final Element[] reports = toArray(Element.class, object.getReports());
104        if (requireMandatoryAttributes) {
105            assertNotEquals(0, reports.length, "DataQuality: must have at least one report.");
106        }
107        for (final Element element : reports) {
108            dispatch(element);
109        }
110    }
111
112    /**
113     * Validates the positional accuracy.
114     *
115     * @param  object  the object to validate, or {@code null}.
116     */
117    public void validate(final PositionalAccuracy object) {
118        if (object == null) {
119            return;
120        }
121        validateElement(object);
122    }
123
124    /**
125     * Validates the properties common to all elements.
126     *
127     * @param  object  the object to validate.
128     */
129    private void validateElement(final Element object) {
130        container.validate(object.getStandaloneQualityReportDetails());
131        for (final Result result : toArray(Result.class, object.getResults())) {
132            dispatch(result);
133        }
134    }
135
136    /**
137     * Validates the descriptive result.
138     *
139     * @param  object  the object to validate, or {@code null}.
140     */
141    public void validate(final DescriptiveResult object) {
142        if (object == null) {
143            return;
144        }
145        validateResult(object);
146        validateMandatory(object.getStatement());
147    }
148
149    /**
150     * Validates the conformance result.
151     *
152     * @param  object  the object to validate, or {@code null}.
153     */
154    public void validate(final ConformanceResult object) {
155        if (object == null) {
156            return;
157        }
158        validateResult(object);
159        Citation specification = object.getSpecification();
160        mandatory(specification, "ConformanceResult: must have a specification.");
161        container.validate(specification);
162        container.validate(object.getExplanation());
163        mandatory(object.pass(), "ConformanceResult: must have a Boolean.");
164    }
165
166    /**
167     * Validates the quantitative result.
168     *
169     * @param  object  the object to validate, or {@code null}.
170     */
171    public void validate(final QuantitativeResult object) {
172        if (object == null) {
173            return;
174        }
175        validateResult(object);
176        int count = toArray(Record.class, object.getValues()).length;
177        if (requireMandatoryAttributes) {
178            assertNotEquals(0, count, "QuantitativeResult: must have at least one value.");
179        }
180    }
181
182    /**
183     * Validates the coverage result.
184     *
185     * @param  object  the object to validate, or {@code null}.
186     */
187    public void validate(final CoverageResult object) {
188        if (object == null) {
189            return;
190        }
191        validateResult(object);
192        mandatory(object.getSpatialRepresentationType(),   "CoverageResult: must have a spatial representation type.");
193        mandatory(object.getResultSpatialRepresentation(), "CoverageResult: must have a result spatial representation.");
194        final RangeDimension[] ranges = toArray(RangeDimension.class, object.getResultContent());
195        if (object.getResultFormat() == null && object.getResultFile() == null && requireMandatoryAttributes) {
196            assertNotEquals(0, ranges.length, "CoverageResult: must have at least one range dimension"
197                    + " when result format and result file are not provided.");
198        }
199    }
200
201    /**
202     * Validates the properties common to all results.
203     *
204     * @param  object  the object to validate.
205     */
206    private void validateResult(final Result object) {
207        container.validate(object.getResultScope());
208    }
209}