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 java.net.URI;
019:
020: /**
021: * A metadata template for a Feature of arbitrary complexity.
022: * <p>
023: * Notes:
024: * <ul>
025: * <li>that this documentation should be read in conjunction with the {@link Feature}API.
026: * <li>the attributes described by this FeatureType <b>and its ancestors </b> define the complete
027: * schema for a Feature
028: * </p>
029: * <p>
030: * This interface answers the question: How do we represent features within GeoTools? Of course, the
031: * most general answer would be: features can be any Java object. However, this is also the least
032: * useful solution because it means that users of features have essentially no way to find out about
033: * the meaning of features other than using Java introspection/reflection. This is too cumbersome
034: * and is insufficient for the goal of creating a simple framework for manipulating and accessing
035: * generic geographic data. The opposite approach might be to define a very constrained set of
036: * possible attributes (that, for example, mirrored Java primitives and OGC simple geometries) and
037: * only allow features of this type.
038: * </p>
039: * <p>
040: * This interface takes a different approach: it defines a minimal ontology for representing a
041: * feature and serves as a consistent framework for defining more constrained (and, therefore, often
042: * more meaningful) feature types. A <code>FeatureType</code> represents features as an object
043: * that contains zero or more attribute objects, one of which will generally be a geometry, but no
044: * geometry and multiple geometries are allowed, according to implementation. Note that instances of
045: * implementations of this class are henceforth referred to as schemas.
046: * </p>
047: * <p>
048: * With oneexceptions, the type of an attribute is considered to be its cannonical definition by the
049: * FeatureType. For example, an attribute type might be a <code>javax.sound.midi.Sequence</code>
050: * object, which contains a <code>float</code> public field called PPQ. The fact that this
051: * attribute exists is not known by the <code>FeatureType</code> itself. If a caller asks this
052: * <code>FeatureType</code> for all of its attributes, the <code>
053: * FeatureType</code> will tell
054: * the caller that it has an attribute of type <code>javax.sound.midi.Sequence</code>, but not
055: * that this attribute has a sub-attribute (field) called PPQ. It is the responsibility of the
056: * callers to understand the objects it is asking for and manipulate them appropriately.
057: * </p>
058: * <p>
059: * The exceptions is for:
060: * <ul>
061: * <li>if the type stored in the <code>FeatureType</code> is a
062: * <code>org.geotools.datasource.Feature</code> type. <br>
063: * In this case, all information about sub-attributes are stored and passed to calling classes upon
064: * request. The style of reference (XPath) is defined in and mediated by <code>FeatureType</code>
065: * implementations.
066: * </ul>
067: * Question: how does one determine the schema for the attribute defined as a FeatureType? I suspect
068: * that FeatureType may be a valid AttributeType? (One needs this schema information before xpath
069: * can be used to query the Feature value.
070: * </p>
071: * <p>
072: * It is the responsibility of the implementing class to ensure that the <code>FeatureType</code>
073: * is always in a valid state. This means that each attribute tuple must be fully initialized and
074: * valid. The minimum valid <code>FeatureType</code> is one with nulls for namespace, type, and
075: * attributes; this is clearly a trivial case, since it is so constrained that it would not allow
076: * for any feature construction. There are a few conventions of which implementers of this interface
077: * must be aware in order to successfully manage a <code>FeatureType</code>:
078: * </p>
079: * <ol>
080: * <li><b>Immutability </b> <br>
081: * <i>FeatureTypes must be implemented as immutable objects! </i> All setting methods have been
082: * removed from this interface, that functionality is now available in the mutable {@link
083: * FeatureTypeFactory}</li>
084: * <li><b>Default Geometries </b> <br>
085: * Note that the FeatureType contains a special methods for handling geometries. The primary
086: * geometry retrieval methods are in <code>Feature</code> because they may change over the life of
087: * the feature, while the schema may not. In cases where there are more than one geometries it is up
088: * to the implementor to determine which is the default geometry. <code>getDefaultGeometry</code>
089: * may return <code>null</code> if there are no geometries in the FeatureType, but if there is one
090: * or more geometry then the method must return one of them, <code>null</code> is never an
091: * acceptable return value.</li>
092: * <li><b>XPath </b> <br>
093: * XPath is the standard used to access all attributes (flat, nested, and multiple), via a single,
094: * unified string. Using XPath to access attributes has the convenient side-benefit of making them
095: * appear to be non-nested and non-multiple to callers with no awareness of XPath. This greatly
096: * simplifies accessing and manipulating data. However, it does put extra burden on the implementers
097: * of <code>FeatureType</code> to understand and correctly implement XPath pointers. Note that the
098: * <code>Feature</code> object does not understand XPath at all and relies on implementors of this
099: * interface to interpret XPath references. Fortunately, XPath is quite simple and has a clearly
100: * written <a href="http://www.w3.org/TR/xpath">specification </a>.</li>
101: * <li><b>Feature Creation </b> <br>
102: * FeatureType also must provide methods for the creation of Features, as specified in
103: * FeatureFactory. The creating FeatureType should check to see if the passed in objects validate
104: * against its AttributeTypes, and if it does should return a new Feature.</li>
105: * </ol>
106: * <h2>Redesign Notes (feature-exp2)</h2>
107: * The main design goal of this is to have FeatureType extend AttributeType. This allows us to
108: * nesting of features much more nicely. We already are going in this direction, with the
109: * FeatureAttributeType buried in DefaultAttribute. This is just making it explicit, so it works
110: * with the complex objects GML can return a lot more sensible. So much of the work in this class is
111: * figuring out what concepts are the same. Some stuff may need to be rethought a bit, as there are
112: * a few subtle assumptions that we are working with flat files. We will revisit this when we
113: * implement choice and multiplicity.
114: * <ul>
115: * <li>got rid of deprecated getNamespace() method that returned a string, replaced it with a URI
116: * return. This has been deprecated for a bit, and was done out of a desire to keep backwards
117: * compatibility with 2.0, but that mission failed, so we're just moving on. This change will break
118: * a few things, but is a good one, people just need to update their client code a bit.
119: * <li>Deprecated getTypeName() to be getName(). They are the same thing, would be nice to get rid
120: * of getTypeName, but it's used super extensively. Though perhaps we could consider keeping it as a
121: * convenience, a bit more explicit, but it seems like overkill.
122: * <li>Updated comments of the AttributeType operations that are inhierited to say what they mean
123: * in the context of a FeatureType.
124: * </ul>
125: * <h2>Redesign Notes (factory-hints)</h2>
126: * The factory-hints design is finally coming through on the promiss of the great geotools factory
127: * design. This design is actualy placing the factory system under application (rather than
128: * 'default') control, as such it is really showing every last place where we did not follow our
129: * architecture.
130: * <ul>
131: * Use Cases:
132: * <li>Custom Feature: <br>
133: * Application spedcifies the use of a custom feature implementation. This is used so an application
134: * interface is supported by each and every feature created.
135: * <li>optiomized coordinate storage <br>
136: * LiteRenderer2 wants Shape2d specific CoordinateSequenceFactory used for all Geometry creation.
137: * The point is to allow only the xy information to be retrieved, and in a format suitable for rapid
138: * reprojection and coversion to a Java2D Shape. Any OpenGL (or Java3D) based renderer would also
139: * run into this need.
140: * </ul>
141: * The second use case is interesting in that LiteRenderer2 will be using the Datastore at the same
142: * time as other threads that want the normal coordinate sequence. So this is a per Query hint.
143: * </ul>
144: * <p>
145: * Consequence: Since FeatureType is immutable, and CoordianteSequence is specified by the
146: * GeometryFactory of the DefaultGeometryAttribute this implys that we have a per Query SchemaType.
147: * </p>
148: * <p>
149: * It strikes me that this is a bad separation of concerns the "schema" should be exactly the same,
150: * it is just the GeometryFactory that controls construction that is in the wrong spot. It should be
151: * a hint, not attached to GeomtryAttributeType.
152: * </p>
153: *
154: * @author Rob Hranac, VFNY
155: * @author Chris Holmes, TOPP
156: * @author David Zwiers, Refractions
157: * @author Jody Garnett, Refractions
158: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/api/src/main/java/org/geotools/feature/FeatureType.java $
159: * @version $Id: FeatureType.java 27002 2007-09-17 03:01:53Z jdeolive $
160: * @see org.geotools.feature.Feature
161: * @see org.geotools.feature.FeatureTypeFactory
162: * @see org.geotools.feature.type.NestedAttributeType
163: * @see org.geotools.feature.DefaultFeatureType
164: */
165: public interface FeatureType {
166: //
167: // XML Mapping Information
168: //
169: // Used for mapping Feature information to Geographical Markup Language,
170: //
171: /**
172: * Gets the global schema namespace.
173: * <p>
174: * This is often used to record the schema prefix (not the URI) required when writing out this
175: * Feature using GML. The supporting application will need to be able to start the GMLWriter off
176: * with the correct URI information so everything makes sense.
177: * </p>
178: * <p>
179: * The Registry interface provided by the data module provides an example of how to store
180: * associate FeatureType and namespace information. Please note that you may not have duplicate
181: * typeNames in the same Namespace.
182: * </p>
183: *
184: * @return Namespace of schema
185: */
186: URI getNamespace();
187:
188: /**
189: * Gets the type name for this schema.
190: * <p>
191: * In GML this must be the element name of the Feature.
192: * </p>
193: *
194: * @return The name of this feature type.
195: */
196: String getTypeName();
197:
198: /**
199: * Test to determine whether this FeatureType is descended from the given FeatureType. Think of
200: * this relationship likes the "extends" relationship in java.
201: *
202: * @param nsURI The namespace URI to use.
203: * @param typeName The typeName.
204: * @return true if descendant, false otherwise.
205: */
206: boolean isDescendedFrom(URI nsURI, String typeName);
207:
208: /**
209: * A convenience method for calling <br>
210: * <code><pre>
211: * FeatureType f1;
212: * FeatureType f2;
213: * f1.isDescendedFrom(f2.getNamespace(), f2.getName());
214: * </pre></code>
215: * <p>
216: * Question: this method duplicates the information provided by getAncestors().
217: * </p>
218: *
219: * @param type The type to compare to.
220: * @return true if descendant, false otherwise.
221: */
222: boolean isDescendedFrom(FeatureType type);
223:
224: /**
225: * Is this FeatureType an abstract type?
226: * <p>
227: * When true is returned instances of this Feature cannot be created, instead a child
228: * FeatureType must use this FeatureType as its ancestor.
229: * </p>
230: *
231: * @return true if abstract, false otherwise.
232: */
233: boolean isAbstract();
234:
235: /**
236: * Obtain an array of this FeatureType's direct ancestors.
237: * Implementors should return a non-null array (may be of length 0).
238: * <p>
239: * <ul>
240: * <li>length 0 - a root FeatureType
241: * <li>length 1 - singe inhieratance
242: * <li>length 1+ - multiple inheiratance, order is not significant
243: * </ul>
244: * </p>
245: * GetAncestors() indicates *just* the direct parents of this FeatureType.
246: * It capures the inheirtance relationship from the OGC overview document.
247: * </p>
248: * <p>
249: * Example Code:<pre><code>
250: * public FeatureType getAncestors()}
251: * return new FeatureType[]{ getSuper(), };
252: * }
253: * </code></pre>
254: * </p>
255: *
256: * @return An array of ancestors.
257: */
258: FeatureType[] getAncestors();
259:
260: /**
261: * Return the direct supertype of this FeatureType.
262: * <p>
263: * This is a conviance method for FeatureType where only single
264: * inheirtance is supported (as is the case with GML).
265: * </p>
266: * <p>
267: * This method will return null for a root FeatureType.
268: * </p>
269: * @return Get the super type, or null for root.
270: */
271:
272: //FeatureType getSuper();
273: /**
274: * Gets the default geometry AttributeType.
275: * <p>
276: * If the FeatureType has more one geometry it is up to the implementor to determine which
277: * geometry is the default. If working with multiple geometries it is best to get the
278: * attributeTypes and iterate through them, checking for instances of GeometryAttribtueType.
279: * </p>
280: * <p>
281: * This should just be used a convenience method when it is known that the features do not have
282: * multiple geometries.
283: * </p>
284: *
285: * @return The attribute type of the default geometry, which will contain the position.
286: */
287: GeometryAttributeType getDefaultGeometry();
288:
289: /**
290: * The number of attribues defined by this schema.
291: * <p>
292: * This method to allows access to the complete schema as defined by this
293: * FeatureType and its ancestors.
294: * </p>
295: * <p>
296: * <ul>
297: * Notes:
298: * <li>
299: * <li>for FeatureType with no super type this count value is the the
300: * same as getAttributeTypes().length.
301: * </p>
302: *
303: * @return number of distinct attributeTypes available, taking ancestors and taking overrides
304: * into account.
305: */
306: int getAttributeCount();
307:
308: /**
309: * Gets the attributeType at this xPath, if the specified attributeType does
310: * not exist then <code>null</code> is returned.
311: * <p>
312: * Question: it is unclear how this interacts with the complete schema defined by this
313: * FeatureType and its ancestors (in which a given xpath may refer to several AttributeTypes as
314: * restrictions are applied.
315: * </p>
316: * <p>
317: * Perhaps this method should be restricted to a FlatFeatureType? Or should have the option of
318: * returning an array of matching AttributeType in order of inheiritence?
319: * </p>
320: *
321: * @param xPath XPath pointer to attribute type.
322: * @return AttributeType, or null if unavaialble
323: */
324: AttributeType getAttributeType(String xPath);
325:
326: /**
327: * Find the position of a given AttributeType.
328: * <p>
329: * Match is based on attribute type name, the resulting index
330: * may be used with getAttributeType( index ).
331: * </p>
332: * @param type The type to search for.
333: * @return -1 if not found, a zero-based index if found.
334: */
335: int find(AttributeType type);
336:
337: /**
338: * Find the position of an AttributeType which matches the given String.
339: * <p>
340: * This index may be used with getAttributeType( index ), the search space is the entire schema
341: * defined by this FeatureType and its ancestors.
342: * </p>
343: *
344: * @param attName the name to look for
345: * @return -1 if not found, zero-based index otherwise
346: */
347: int find(String attName);
348:
349: /**
350: * Gets the schema attributeType at the specified index.
351: * <p>
352: * The index is specified with respect to the entire Schema (as defined by this FeatureType and
353: * it's ancestors).
354: * <p>
355: * <ul>
356: * The index value should not be used with either:
357: * <li>FeatureType.getAttributeTypes()[index] - as it defines only attributes contributed by
358: * this FeatureType
359: * <li>Feature.getAttribute( index ) - as attributes order may or may not be in sequence
360: * </ul>
361: * </p>
362: *
363: * @param position a integer index into the complete schema represented by
364: * this FeatureType and its ancestors
365: *
366: * @return the attribute type at the specified position
367: */
368: AttributeType getAttributeType(int position);
369:
370: /**
371: * AttributeTypes for this FeatureType, all attributes defined by this FeatureType
372: * and its super types define schema for feature instances.
373: * <p>
374: * The provided array of AttributeTypes should be considered as adding to (or overriding) the
375: * the AttribtueTypes defined by this FeatureTypes ancestors.
376: * </p>
377: * <p>
378: * Note Well: Client code should not consider the index provided by the find( attName ) method
379: * as a valid index into the returned array.
380: * </p>
381: *
382: * @return Array of AttributeType describing this schema, array may be length 0, but should
383: * not be null
384: */
385: AttributeType[] getAttributeTypes();
386:
387: //
388: // Depreicated AttributeType handling code
389: //
390: // This is origional Geotools 2.0 api that is depricated and will
391: // be removed as part of Geotools 2.2.
392: //
393: /**
394: * This is only used twice in the whole geotools code base, and one of those is for a test, so
395: * we're removing it from the interface. If getAttributeType does not have the AttributeType it
396: * will just return null. Gets the number of occurrences of this attribute.
397: * <p>
398: * Question: the comment says we are removing this, but it is not depricated? And how the heck
399: * can the number of occurances out of a boolean.
400: * </p>
401: *
402: * @deprecated It seems this method is ill concieved, use getAttributeType( xpath ) != null as a
403: * replacement
404: * @param xPath XPath pointer to attribute type.
405: * @return Number of occurrences.
406: */
407: boolean hasAttributeType(String xPath);
408:
409: //
410: // This is code that was available in Geotools 2.0 as part of the
411: // FeatureFactory API, In geotools 2.1 we are providing a clear
412: // separation between schema information and construction.
413: //
414: /**
415: * Create a duplicate of the provided feature, must delegate to an appropriate FeatureFactory
416: * create method.
417: * <p>
418: * The implementation is assumed to make use of AttributeType duplicate as required for a deep
419: * copy.
420: * </p>
421: *
422: * //@deprecated This method will be removed in 2.2, please use FeatureFactory obtained from FactoryFinder
423: * @param feature
424: * @return a deep copy of feature
425: * @throws IllegalAttributeException
426: */
427: Feature duplicate(Feature feature) throws IllegalAttributeException;
428:
429: /**
430: * Creates a new feature, with a generated unique featureID.
431: * <p>
432: * Generating a FeatureID is less than ideal, as a FeatureID should be something
433: * special about the "real world object" being modeled as a feature.
434: * <p>
435: * As an example: the "Effiel Tower" is a great feature id (there is only one) and we can
436: * use that Feature ID in serveral systems:
437: * <ul>
438: * <li>In a tour guide FeatureTypes one which records (NAME, LOCATION, COST); and
439: * <li>In a historical reference (NAME, LOCATION, HIEGHT, DATE, HISTORY)
440: * </ul>
441: * <p>
442: * Explicitly a FeatureID should be persistant over time, and between systems.
443: * <p>
444: * The FeatureIDs "generated" by this method are generally created by a datasource.
445: * This method is more for testing that doesn't need featureID.
446: * </p>
447: * <p>
448: * Warning: This class does not follow the geotools guidelines of sepearting out
449: * Interface from Factory, in geotools 2.3 there will be a formal FeatureFactory
450: * allowing you to provide application specific FeatureImplementations as an orthogonal
451: * concern to definition of type.
452: * </p>
453: *
454: * @param attributes the array of attribute values
455: * @return The created feature
456: * @throws IllegalAttributeException if the FeatureType does not validate the attributes.
457: */
458: Feature create(Object[] attributes)
459: throws IllegalAttributeException;
460:
461: /**
462: * Scheduled for removal in Geotools 2.2, please use FeatureFactory.
463: * <p>
464: * Creates a new feature, with the indicated featureID.
465: * </p>
466: *
467: * @param attributes the array of attribute values.
468: * @param featureID the feature ID.
469: * @return the created feature.
470: * @throws IllegalAttributeException if the FeatureType does not validate the attributes.
471: */
472: Feature create(Object[] attributes, String featureID)
473: throws IllegalAttributeException;
474:
475: /**
476: * FeatureType check based on namespace, typeName, attributes and ancestors.
477: * <p>
478: * Conceptually FeatureType equality is supped to indicate an exact match based AttributeType
479: * and Ancestors. The geotools models includes additional information of namespace
480: * and typename.
481: * </p>
482: * <p>
483: * As far as the geotools data model is concerned any FeatureType implementation should be able
484: * to be subsituted for another. (An actually application may provided an implementation that
485: * provdes tracking of metadata such as creation history, or support for additional interfaces).
486: * </p>
487: * <p>
488: * Required implementation:<pre><code>
489: * </code></pre>
490: * A sample implementation is provided in FeatureTypes.equals( FeatureType, FeatureType ).
491: * </p>
492: * <p>
493: * Questions:
494: * <br>Q: You may wonder why namespace and typeName are not enought?
495: * <br>A: Geotools often returns a "limitied" schema in response to a query where only a subset
496: * of the attributes are requested.
497: * <br>Q: Doesn't that still indicate the same schema?
498: * <br>A: Yes it kind of should, a GML application (such as GeoServer) has to actually follow the
499: * application schema and include attributes required by the schema (but not request by the query).
500: * This library is more lax in its treatment, and expects you to uses isDecendedFrom as required.
501: * </p>
502: */
503: public boolean equals(Object arg0);
504:
505: /**
506: * Hascode based on namespace, typeName, attributes and ancestors.
507: * <p>
508: * Hascode is always a matched set with an equals implementation, please see the javadocs
509: * for equals for a detailed discussion.
510: * </p>
511: * @see java.lang.Object#hashCode()
512: */
513: public int hashCode();
514: }
|