001/*
002 *    GeoAPI - Java interfaces for OGC/ISO standards
003 *    Copyright © 2004-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.feature;
019
020
021/**
022 * An instance of a {@link FeatureType} containing values for a real-world phenomena.
023 * Each feature instance can provide values for the following properties:
024 *
025 * <ul>
026 *   <li>{@linkplain Attribute          Attributes}, which may be {@linkplain DynamicAttribute dynamic}</li>
027 *   <li>{@linkplain FeatureAssociation Associations to other features}</li>
028 *   <li>{@linkplain Operation          Operations}</li>
029 * </ul>
030 *
031 * {@code Feature} can be instantiated by calls to {@link FeatureType#newInstance()}.
032 *
033 * <h2>Simple features</h2>
034 * A feature is said “simple” if it complies to all the following conditions:
035 * <ul>
036 *   <li>the feature allows only attributes and operations (no associations),</li>
037 *   <li>the multiplicity of all attributes is constrained to [1 … 1].</li>
038 * </ul>
039 *
040 * <h2>Moving features</h2>
041 * A feature is a moving feature if it complies to at least one of the following conditions:
042 * <ul>
043 *   <li>the feature contains {@linkplain DynamicAttribute dynamic attributes},</li>
044 *   <li>the geometry value of an {@linkplain Attribute attribute} is a trajectory.</li>
045 * </ul>
046 *
047 * @author  Jody Garnett (Refractions Research, Inc.)
048 * @author  Justin Deoliveira (The Open Planning Project)
049 * @author  Martin Desruisseaux (Geomatys)
050 * @version 3.1
051 * @since   3.1
052 *
053 * @see FeatureType
054 */
055public interface Feature {
056    /**
057     * Returns information about the feature (name, characteristics, <i>etc.</i>).
058     *
059     * @return information about the feature.
060     */
061    FeatureType getType();
062
063    /**
064     * Returns the property (attribute, feature association or operation result) of the given name.
065     * If the property type is a parameterless {@link Operation}, then this method may return
066     * the result of {@linkplain Operation#apply executing} the operation on this feature,
067     * at implementation choice.
068     *
069     * <h4>Performance note</h4>
070     * This method returns the property <em>instance</em>. If only the property <em>value</em> is desired,
071     * then {@link #getPropertyValue(String)} is preferred because it gives to implementations a chance to
072     * avoid the creation of {@link Attribute} or {@link FeatureAssociation} instances.
073     *
074     * @param  name  the property name.
075     * @return the property of the given name (never {@code null}).
076     * @throws PropertyNotFoundException if the given argument is not a property name of this feature.
077     *
078     * @see #getPropertyValue(String)
079     * @see FeatureType#getProperty(String)
080     */
081    Property getProperty(String name) throws PropertyNotFoundException;
082
083    /**
084     * Sets the property (attribute or feature association).
085     * The given property shall comply to the following conditions:
086     *
087     * <ul>
088     *   <li>It must be non-null.</li>
089     *   <li>Its {@linkplain Property#getName() name} shall be the name of the property to set in this feature.</li>
090     *   <li>Its type shall be the same instance as the {@linkplain FeatureType#getProperty(String) property type}
091     *       defined by the feature type for the above name. In other words, the following condition shall hold:</li>
092     * </ul>
093     *
094     * {@snippet lang="java" :
095     * assert property.getType() == getType().getProperty(property.getName());
096     * }
097     *
098     * <h4>Usage note</h4>
099     * This method is useful for storing non-default {@code Attribute} or {@code Association} implementations in
100     * this feature. When default implementations are sufficient, the {@link #setPropertyValue(String, Object)}
101     * method is preferred.
102     *
103     * @param  property  the property to set.
104     * @throws PropertyNotFoundException if the name of the given property is not a property name of this feature.
105     * @throws InvalidPropertyValueException if the value of the given property is not valid.
106     * @throws IllegalArgumentException if the property cannot be set for another reason
107     *         (e.g. a library may accept only some specific property instances).
108     *
109     * @see #setPropertyValue(String, Object)
110     */
111    void setProperty(Property property) throws IllegalArgumentException;
112
113    /**
114     * Returns the value for the property of the given name.
115     * This convenience method is equivalent to invoking {@link #getProperty(String)} for the given name,
116     * then to perform one of the following actions depending on the property type and the multiplicity:
117     *
118     * <table class="ogc">
119     *   <caption>Class of returned value</caption>
120     *   <tr><th>Property type</th>                  <th>max. occurs</th> <th>Method invoked</th>                         <th>Return type</th></tr>
121     *   <tr><td>{@link AttributeType}</td>          <td>0 or 1</td>      <td>{@link Attribute#getValue()}</td>           <td>{@link Object}</td></tr>
122     *   <tr><td>{@code AttributeType}</td>          <td>2 or more</td>   <td>{@link Attribute#getValues()}</td>          <td>{@code Collection<?>}</td></tr>
123     *   <tr><td>{@link FeatureAssociationRole}</td> <td>0 or 1</td>      <td>{@link FeatureAssociation#getValue()}</td>  <td>{@link Feature}</td></tr>
124     *   <tr><td>{@code FeatureAssociationRole}</td> <td>2 or more</td>   <td>{@link FeatureAssociation#getValues()}</td> <td>{@code Collection<Feature>}</td></tr>
125     * </table>
126     *
127     * <h4>Note on occurrences</h4>
128     * “max. occurs” is the {@linkplain AttributeType#getMaximumOccurs() maximum number of occurrences}
129     * and does not depend on the actual number of values. If an attribute allows more than one value,
130     * then this method will always return a collection for that attribute even if the collection is empty.
131     *
132     * @param  name  the property name.
133     * @return value of the specified property,
134     *         or the {@linkplain AttributeType#getDefaultValue() default value} (which may be {@code null}} if none.
135     * @throws PropertyNotFoundException if the given argument is not an attribute or association name of this feature.
136     *
137     * @see Attribute#getValue()
138     * @see FeatureAssociation#getValue()
139     */
140    Object getPropertyValue(String name) throws PropertyNotFoundException;
141
142    /**
143     * Sets the value for the property of the given name.
144     *
145     * <h4>Note on validation</h4>
146     * The verifications performed by this method is implementation dependent.
147     * For performance reasons, an implementation may verify only the most basic constraints
148     * and offer another method for performing more extensive validation.
149     * Implementations should document their validation process.
150     *
151     * @param  name   the property name.
152     * @param  value  the new value for the specified property (may be {@code null}).
153     * @throws PropertyNotFoundException if the given name is not an attribute or association name of this feature.
154     * @throws ClassCastException if the value is not assignable to the expected value class.
155     * @throws InvalidPropertyValueException if the given value is not valid for a reason other than its type.
156     *
157     * @see Attribute#setValue(Object)
158     * @see FeatureAssociation#setValue(Feature)
159     */
160    void setPropertyValue(final String name, final Object value) throws IllegalArgumentException;
161
162    /**
163     * Returns the value for the property of the given name if that property exists, or a fallback value otherwise.
164     * This method is equivalent to the following code, but potentially more efficient when the property does not exist:
165     *
166     * {@snippet lang="java" :
167     * try {
168     *     return getPropertyValue(name);
169     * } catch (PropertyNotFoundException ignore) {
170     *     return missingPropertyFallback
171     * }}
172     *
173     * Note that if a property of the given name exists but has no value, then this method returns
174     * the {@linkplain AttributeType#getDefaultValue() default value} (which may be {@code null}).
175     * <i>Property without value</i> is not equivalent to <i>non-existent property</i>.
176     *
177     * @param  name  the property name.
178     * @param  missingPropertyFallback  the (potentially {@code null}) value to return
179     *         if no attribute or association of the given name exists.
180     * @return value or default value of the specified property, or {@code missingPropertyFallback}
181     *         if no attribute or association of that name exists. This value may be {@code null}.
182     */
183    Object getValueOrFallback(String name, Object missingPropertyFallback);
184}