001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.feature;
017:
018: import com.vividsolutions.jts.geom.Envelope;
019: import com.vividsolutions.jts.geom.Geometry;
020: import org.geotools.geometry.jts.ReferencedEnvelope;
021:
022: /**
023: * <p>
024: * Represents a feature of arbitrary complexity.
025: * <p>
026: * This interface answers the question: How do we store feature attributes?
027: * (The answer to the more useful question, How do we access feature attribute,
028: * is contained in the Expression class.
029: * <p>
030: * <p>
031: * Warning: We are revising the Feature Model to be more complete in the
032: * next round of GeoTools. If you do any data access in your classes please try
033: * and make use of Expression to access your information, if you do this you will
034: * not be affected by the change (beyond a few search and replace operations).
035: * </p>
036: * The most generic approach would be to pass all feature attributes as objects
037: * and use Java variable and method references to access them. However, this is
038: * also the most useless approach because it establishes no unified methods for getting
039: * attribute information (since it is totally Object dependent), without
040: * elaborate reflection/introspection, which is inconvenient to use. Unlike
041: * its {@link FeatureType} counterpart, this interface does not attempt to
042: * serve as a typing framework. Rather, multiple implementations of this
043: * interface should generally be for performance reasons.
044: * </p>
045: *
046: * <p>
047: * This interface serves two important purposes. Most obviously, it gives
048: * users of features a unified, consistent framework for accessing and
049: * manipulating feature data. Perhaps more importantly, the
050: * <code>FeatureType</code> and <code>Feature</code> interfaces also work
051: * together to give implementers a framework for constraining and enforcing
052: * constraints (respectively) on allowed feature types. As such, this
053: * interface is as general as possible in terms of the types of objects to
054: * which it provides access. Keep in mind that creating new features is
055: * relatively difficult and should only be done to optimize performance for
056: * highly constrained schema types. For the vast majority of schemas, the
057: * generic feature implementation will work fine.
058: * </p>
059: *
060: * <p>
061: * <b>Notes for Feature Clients:</b><br>
062: * Clients should always use feature accessor methods (getAttribute and
063: * setAttribute) to modify the state of internal attribute objects. It is
064: * possible that some feature implementations will allow object state changes
065: * by clients outside of the class, but this is strongly discouraged. In
066: * general, feature implementations will make defensive copies of objects
067: * passed to clients and it is therefore not guaranteed that client state
068: * changes that take place outside of the feature will be reflected in the
069: * internal state of the feature object! <i>For this reason, clients should
070: * always use the set methods to change feature attribute object states!</i>
071: * </p>
072: *
073: * <p>
074: * <b>Notes for Feature Implementers:</b><br>
075: * It is the responsibility of the implementing class to ensure that the
076: * <code>Feature</code> attributes stay synchronized with its FeatureType
077: * definition. <i>Features should never get out of synch with their declared
078: * schemas and should never alter their schemas!</i> There are four
079: * conventions of which implementers of this interface must be aware in order
080: * to successfully manage a <code>Feature</code>:
081: * </p>
082: *
083: * <ol>
084: * <li>
085: * <b>FeatureType Reference</b><br>
086: * Features must always hold a single (immutable: see
087: * <code>FeatureType</code>) schema reference and this reference should not be
088: * altered after a feature has been created. To ensure this, is is strongly
089: * recommended that features take a valid reference to an existing immutable
090: * schema in its constructor and declare that reference final.
091: * </li>
092: * <li>
093: * <b>Default Geometry</b><br>
094: * Each feature must have a default geometry, but this primary geometry may be
095: * null. This means that a feature may contain no geometries, but it must
096: * always have a method for accessing a geometry object (even if it is null).
097: * It also means that a feature with multiple geometries must pick one as its
098: * default geometry. Note that the designation of the default geometry is
099: * stored as part of the <code>FeatureType</code> and is therefore immmutable.
100: * </li>
101: * <li>
102: * <b>Attributes</b><br> All features contain zero or more attributes, which
103: * can have one or more occurrences inside the feature. Attributes may be any
104: * valid Java object. If attributes are instances of <code>Feature</code>,
105: * they are handled specially by the <code>Feature</code> methods, in that
106: * their attributes may be accessed directly by their containing feature. All
107: * other object variables and methods must be accessed through the objects
108: * themselves. It is up to implementers of <code>Feature</code> to make sure
109: * that each attribute value conforms to its internal schema. A feature
110: * should never reach a state where its attributes (or sub-attributes) do not
111: * conform to their <code>FeatureType</code> definitions. There are three
112: * ways to implement this. The first is to simply make features immutable;
113: * however, given the ubiquity and required flexibility of features, this is
114: * likely not possible. The second (and second easiest), is to make all
115: * feature attributes immutable. For most cases, this is probably the best way
116: * to handle this issue. The third way, is to never give out a reference that
117: * would allow a client to change an attribute object's class (most obviously,
118: * an array reference). Generally speaking, features should attempt to
119: * minimize external object references by attempting to clone incoming
120: * attributes before adding them and outgoing attributes before sending them.
121: * For features with non-cloneable attributes, of course, this is not
122: * possible, so this is left to the discretion of the implementor.
123: * </li>
124: * <li>
125: * <b>Constructors</b><br> Constructors should take arguments with enough
126: * information to create a valid representation of the feature. They should
127: * also always include a valid schema that can be used to check the proposed
128: * attributes. This is necessary to ensure that the feature is always in a
129: * valid state, relative to its schema.
130: * </li>
131: * <li>
132: * <b>hashCode() and equals(Object other)</b><br>
133: * Determining equality and equivalence for Feature instances is of utmost
134: * importance. This must be done in a constistent manner, as many other areas
135: * of geotools will rely on these relations. See java.lang.Object for details.
136: * </li>
137: * </ol>
138: *
139: *
140: * @author James Macgill, CCG
141: * @author Rob Hranac, TOPP
142: * @author Ian Schneider, USDA-ARS
143: * @author dzwiers
144: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/api/src/main/java/org/geotools/feature/Feature.java $
145: * @version $Id: Feature.java 27002 2007-09-17 03:01:53Z jdeolive $
146: *
147: * @see org.geotools.feature.FeatureType
148: * @see org.geotools.feature.DefaultFeature
149: */
150: public interface Feature {
151: /**
152: * Gets a reference to the schema for this feature.
153: *
154: * @return A reference to this feature's schema.
155: */
156: FeatureType getFeatureType();
157:
158: /**
159: * Gets the unique feature ID for this feature.
160: *
161: * @return Unique identifier for this feature.
162: */
163: String getID();
164:
165: /**
166: * Copy all the attributes of this Feature into the given array. If the
167: * argument array is null, a new one will be created. Gets all attributes
168: * from this feature, returned as a complex object array. This array
169: * comes with no metadata, so to interpret this collection the caller
170: * class should ask for the schema as well. This array may have multiple
171: * entries for each AttributeType depending on the AttributeType's
172: * multiplicity.
173: *
174: * @param attributes An array to copy attributes into. May be null.
175: *
176: * @return The array passed in, or a new one if null.
177: */
178: Object[] getAttributes(Object[] attributes);
179:
180: /**
181: * Gets an attribute for this feature at the location specified by xPath.
182: * Due to the complex nature of xpath, a List of all valid values will be
183: * returned when an attribute is requested. These values can range from
184: * complete Feature Collections to single primative attribute values. When
185: * a particular instance of the Attribute is requested, then the Object
186: * will be returned. Simply put, in the general case we are assuming the
187: * existance of multiplicity, so specify which instance you want or you
188: * get them all. Example of getting a list: ./road returns the
189: * List of road attribute instances Example of getting an Object:
190: * ./road[0] returns the first road
191: *
192: * @param xPath XPath representation of attribute location.
193: *
194: * @return A List of copies of the requested attribute, null if the
195: * requested xpath is not found, or NULL_ATTRIBUTE.
196: */
197: Object getAttribute(String xPath);
198:
199: /**
200: * Gets an attribute by the given zero-based index. This index is based on
201: * the values within the Feature as opposed to the AttributeType
202: * declaration. To get the values for the 5th attributeType, use the
203: * schema to determine the xPath and class the getAttribute(xPath)
204: * method.
205: *
206: * @param index The requested index. Must be 0 <= idx <
207: * getNumberOfAttributes().
208: *
209: * @return A copy of the requested attribute, or NULL_ATTRIBUTE.
210: *
211: * @see Feature#getAttribute(String)
212: */
213: Object getAttribute(int index);
214:
215: /**
216: * Sets an attribute by the given zero-based index. This index is based on
217: * the values within the Feature as opposed to the AttributeType
218: * declaration. To get the values for the 5th attributeType, use the
219: * schema to determine the xPath and class the setAttribute(xPath,val)
220: * method.
221: *
222: * @param position The requested index. Must be 0 <= idx <
223: * getNumberOfAttributes()
224: * @param val An object representing the attribute being set
225: *
226: * @throws IllegalAttributeException if the passed in val does not validate
227: * against the AttributeType at that position.
228: * @throws ArrayIndexOutOfBoundsException if an invalid position is given
229: *
230: * @see Feature#setAttribute(String, Object)
231: */
232: void setAttribute(int position, Object val)
233: throws IllegalAttributeException,
234: ArrayIndexOutOfBoundsException;
235:
236: /**
237: * Get the number of attributes this feature has. This is NOT simply a
238: * convenience method for calling
239: * getFeatureType().getNumberOfAttributes(). This is the same as calling
240: * getAttributes(null).length. This represents the number of actual
241: * attribute values in the feature, and may differ from the number of
242: * AttributeTypes defined in the FeatureType based on the multiplicity of
243: * the AttributeTypes.
244: *
245: * @return The total number of attributes this Feature contains.
246: */
247: int getNumberOfAttributes();
248:
249: /**
250: * Sets a single attribute for this feature, passed as a complex object. If
251: * the attribute does not exist or the object does not conform to the
252: * internal schema, an exception is thrown. Checking this is, of course,
253: * left to the feature to do internally. Well behaved features should
254: * always fully check the passed attributes against thire schema before
255: * adding them. NOTE: The xPath may contain instance information about
256: * multiplicity, for example: ./road[3] which is the third road
257: * attribute in this feature.
258: *
259: * @param xPath XPath representation of attribute location.
260: * @param attribute Feature attribute to set.
261: *
262: * @throws IllegalAttributeException If the attribute is illegal for the
263: * path specified.
264: */
265: void setAttribute(String xPath, Object attribute)
266: throws IllegalAttributeException;
267:
268: /**
269: * Gets the default geometry for this feature.
270: *
271: * <p>
272: * This method will return <code>null</code> if no DefaultGeometry has been
273: * defined by the schema.
274: * </p>
275: *
276: * @return Default geometry for this feature, or <code>null</code>
277: */
278: Geometry getDefaultGeometry();
279:
280: /**
281: * Sets the default geometry for this feature.
282: *
283: * @param geometry The geometry to set.
284: *
285: * @throws IllegalAttributeException If the AttributeType is not a
286: * geometry, or is invalid for some other reason.
287: */
288: void setDefaultGeometry(Geometry geometry)
289: throws IllegalAttributeException;
290:
291: /**
292: * Get the total bounds of this feature which is calculated by doing a
293: * union of the bounds of each geometry this feature is associated with.
294: *
295: * <p>
296: * This method will return an empty Envelope if the feature contains no
297: * geometry information.
298: * </p>
299: *
300: * @return An Envelope containing the total bounds of this Feature.
301: */
302: ReferencedEnvelope getBounds();
303:
304: /**
305: * Not straight forward, this is a "null" object to represent the value
306: * null for a given attribute which is nullable.
307: */
308: static final class NULL implements Comparable {
309: /**
310: * Implementation of Comparable.
311: *
312: * @param o The other thing to compare to.
313: *
314: * @return 0 if null or this, 1 for all others.
315: */
316: public int compareTo(Object o) {
317: if (o == null) {
318: return 0;
319: }
320:
321: if (o == this ) {
322: return 0;
323: }
324:
325: return 1;
326: }
327: }
328: }
|