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.metadata;
033
034import java.util.Date;
035import org.opengis.metadata.*;
036import org.opengis.metadata.citation.*;
037import org.opengis.util.InternationalString;
038import org.opengis.test.ValidatorContainer;
039
040import static org.junit.Assert.*;
041
042
043/**
044 * Validates {@link Citation} and related objects from the
045 * {@code org.opengis.metadata.citation} package.
046 *
047 * <p>This class is provided for users wanting to override the validation methods. When the default
048 * behavior is sufficient, the {@link org.opengis.test.Validators} static methods provide a more
049 * convenient way to validate various kinds of objects.</p>
050 *
051 * @author  Martin Desruisseaux (Geomatys)
052 * @version 3.1
053 * @since   2.2
054 */
055public class CitationValidator extends MetadataValidator {
056    /**
057     * Creates a new validator instance.
058     *
059     * @param container  the set of validators to use for validating other kinds of objects
060     *                   (see {@linkplain #container field javadoc}).
061     */
062    public CitationValidator(final ValidatorContainer container) {
063        super(container, "org.opengis.metadata.citation");
064    }
065
066    /**
067     * Validates the given citation.
068     *
069     * @param  object  the object to validate, or {@code null}.
070     */
071    public void validate(final Citation object) {
072        if (object == null) {
073            return;
074        }
075        validateMandatory(object.getTitle());
076        validateOptional (object.getEdition());
077        for (final InternationalString e : toArray(InternationalString.class, object.getAlternateTitles())) {
078            container.validate(e);
079        }
080        for (final Identifier e : toArray(Identifier.class, object.getIdentifiers())) {
081            container.validate(e);
082        }
083        container.validate(object.getOtherCitationDetails());
084        validate(toArray(CitationDate.class, object.getDates()));
085        for (final Responsibility e : toArray(Responsibility.class, object.getCitedResponsibleParties())) {
086            validate(e);
087        }
088    }
089
090    /**
091     * Validates citation dates. If more than one dates is given, then this method will check
092     * for the following constraints:
093     *
094     * <ul>
095     *   <li>{@link DateType#CREATION} shall be before or equals to all other type of dates, ignoring user-defined codes.</li>
096     *   <li>{@link DateType#LAST_UPDATE} shall be before or equals to {@link DateType#NEXT_UPDATE}.</li>
097     *   <li>{@link DateType#VALIDITY_BEGINS} shall be before or equals to {@link DateType#VALIDITY_EXPIRES}.</li>
098     * </ul>
099     *
100     * Those constraints are verified in their iteration order. It is possible for example to have more than one
101     * (<var>validity begins</var>, <var>validity expires</var>) pair.
102     *
103     * @param dates  the citation dates to validate.
104     *
105     * @since 3.1
106     */
107    public void validate(final CitationDate... dates) {
108        if (dates == null) {
109            return;
110        }
111        Date creation       = null;
112        Date lastUpdate     = null;
113        Date validityBegins = null;
114        final int lastOrdinal = DateType.DISTRIBUTION.ordinal();
115        for (final CitationDate date : dates) {
116            if (date != null) {
117                final DateType type = date.getDateType();
118                final Date     time = date.getDate();
119                mandatory("CitationDate: shall have a date type.", type);
120                mandatory("CitationDate: shall have a timestamp.", time);
121                if (type != null && time != null) {
122                    if (type.equals(DateType.CREATION)) {
123                        creation = time;
124                    } else if (type.equals(DateType.LAST_UPDATE)) {
125                        lastUpdate = time;
126                    } else if (type.equals(DateType.NEXT_UPDATE)) {
127                        assertOrdered(DateType.LAST_UPDATE, lastUpdate, DateType.NEXT_UPDATE, time);
128                    } else if (type.equals(DateType.VALIDITY_BEGINS)) {
129                        validityBegins = time;
130                    } else if (type.equals(DateType.VALIDITY_EXPIRES)) {
131                        assertOrdered(DateType.VALIDITY_BEGINS, validityBegins, DateType.VALIDITY_EXPIRES, time);
132                    }
133                    if (type.ordinal() <= lastOrdinal) {
134                        assertOrdered(DateType.CREATION, creation, type, time);
135                    }
136                }
137            }
138        }
139    }
140
141    /**
142     * Asserts that the date {@code d2} is equals or after {@code d1}.
143     */
144    private static void assertOrdered(final DateType t1, final Date d1, final DateType t2, final Date d2) {
145        if (d1 != null && d2.before(d1)) {
146            fail("The ‘" + t2.identifier() + "’ date (" + d2 + ") shall be equal or after "
147               + "the ‘" + t1.identifier() + "’ date (" + d1 + ").");
148        }
149    }
150
151    /**
152     * Validates the given responsible party.
153     *
154     * @param  object  the object to validate, or {@code null}.
155     *
156     * @since 3.1
157     */
158    public void validate(final Responsibility object) {
159        if (object == null) {
160            return;
161        }
162        mandatory("Responsibility: shall have a role.", object.getRole());
163        for (final Party e : toArray(Party.class, object.getParties())) {
164            validate(e);
165        }
166    }
167
168    /**
169     * Validates the given party.
170     *
171     * @param  object  the object to validate, or {@code null}.
172     *
173     * @since 3.1
174     */
175    public void validate(final Party object) {
176        if (object == null) {
177            return;
178        }
179        boolean isMandatory = true;
180        if (object instanceof Individual) {
181            isMandatory &= isNullOrEmpty(((Individual) object).getPositionName());
182        }
183        if (object instanceof Organisation) {
184            isMandatory &= isNullOrEmpty(((Organisation) object).getLogo());
185        }
186        if (isMandatory) {
187            mandatory("Party: shall have a name.", object.getName());
188        }
189        for (final Contact e : toArray(Contact.class, object.getContactInfo())) {
190            validate(e);
191        }
192    }
193
194    /**
195     * Validates the given contact information.
196     *
197     * @param  object  the object to validate, or {@code null}.
198     *
199     * @since 3.1
200     */
201    public void validate(final Contact object) {
202        if (object == null) {
203            return;
204        }
205        for (final Telephone e : toArray(Telephone.class, object.getPhones())) {
206            validate(e);
207        }
208        for (final Address e : toArray(Address.class, object.getAddresses())) {
209            validate(e);
210        }
211        for (final OnlineResource e : toArray(OnlineResource.class, object.getOnlineResources())) {
212            validate(e);
213        }
214        validateOptional(object.getHoursOfService());
215        validateOptional(object.getContactInstructions());
216    }
217
218    /**
219     * Validates the given telephone information.
220     *
221     * @param  object  the object to validate, or {@code null}.
222     *
223     * @since 3.1
224     */
225    public void validate(final Telephone object) {
226        if (object == null) {
227            return;
228        }
229        mandatory("Telephone: shall have a number.", object.getNumber());
230    }
231
232    /**
233     * Validates the given address.
234     *
235     * @param  object  the object to validate, or {@code null}.
236     *
237     * @since 3.1
238     */
239    public void validate(final Address object) {
240        if (object == null) {
241            return;
242        }
243        validate(object.getDeliveryPoints());
244        validateOptional(object.getCity());
245        validateOptional(object.getAdministrativeArea());
246        validateOptional(object.getCountry());
247        validate(object.getElectronicMailAddresses());
248    }
249
250    /**
251     * Validates the given online resource.
252     *
253     * @param  object  the object to validate, or {@code null}.
254     *
255     * @since 3.1
256     */
257    public void validate(final OnlineResource object) {
258        if (object == null) {
259            return;
260        }
261        mandatory("OnlineResource: shall have a linkage.", object.getLinkage());
262        validateOptional(object.getDescription());
263    }
264}