/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.feature; import java.net.URI; import org.opengis.feature.simple.SimpleFeatureType; /** * A metadata template for a Feature of arbitrary complexity. * <p> * Notes: * <ul> * <li>that this documentation should be read in conjunction with the {@link Feature}API. * <li>the attributes described by this FeatureType <b>and its ancestors </b> define the complete * schema for a Feature * </p> * <p> * This interface answers the question: How do we represent features within GeoTools? Of course, the * most general answer would be: features can be any Java object. However, this is also the least * useful solution because it means that users of features have essentially no way to find out about * the meaning of features other than using Java introspection/reflection. This is too cumbersome * and is insufficient for the goal of creating a simple framework for manipulating and accessing * generic geographic data. The opposite approach might be to define a very constrained set of * possible attributes (that, for example, mirrored Java primitives and OGC simple geometries) and * only allow features of this type. * </p> * <p> * This interface takes a different approach: it defines a minimal ontology for representing a * feature and serves as a consistent framework for defining more constrained (and, therefore, often * more meaningful) feature types. A <code>FeatureType</code> represents features as an object * that contains zero or more attribute objects, one of which will generally be a geometry, but no * geometry and multiple geometries are allowed, according to implementation. Note that instances of * implementations of this class are henceforth referred to as schemas. * </p> * <p> * With oneexceptions, the type of an attribute is considered to be its cannonical definition by the * FeatureType. For example, an attribute type might be a <code>javax.sound.midi.Sequence</code> * object, which contains a <code>float</code> public field called PPQ. The fact that this * attribute exists is not known by the <code>FeatureType</code> itself. If a caller asks this * <code>FeatureType</code> for all of its attributes, the <code> * FeatureType</code> will tell * the caller that it has an attribute of type <code>javax.sound.midi.Sequence</code>, but not * that this attribute has a sub-attribute (field) called PPQ. It is the responsibility of the * callers to understand the objects it is asking for and manipulate them appropriately. * </p> * <p> * The exceptions is for: * <ul> * <li>if the type stored in the <code>FeatureType</code> is a * <code>org.geotools.datasource.Feature</code> type. <br> * In this case, all information about sub-attributes are stored and passed to calling classes upon * request. The style of reference (XPath) is defined in and mediated by <code>FeatureType</code> * implementations. * </ul> * Question: how does one determine the schema for the attribute defined as a FeatureType? I suspect * that FeatureType may be a valid AttributeType? (One needs this schema information before xpath * can be used to query the Feature value. * </p> * <p> * It is the responsibility of the implementing class to ensure that the <code>FeatureType</code> * is always in a valid state. This means that each attribute tuple must be fully initialized and * valid. The minimum valid <code>FeatureType</code> is one with nulls for namespace, type, and * attributes; this is clearly a trivial case, since it is so constrained that it would not allow * for any feature construction. There are a few conventions of which implementers of this interface * must be aware in order to successfully manage a <code>FeatureType</code>: * </p> * <ol> * <li><b>Immutability </b> <br> * <i>FeatureTypes must be implemented as immutable objects! </i> All setting methods have been * removed from this interface, that functionality is now available in the mutable {@link * FeatureTypeFactory}</li> * <li><b>Default Geometries </b> <br> * Note that the FeatureType contains a special methods for handling geometries. The primary * geometry retrieval methods are in <code>Feature</code> because they may change over the life of * the feature, while the schema may not. In cases where there are more than one geometries it is up * to the implementor to determine which is the default geometry. <code>getDefaultGeometry</code> * may return <code>null</code> if there are no geometries in the FeatureType, but if there is one * or more geometry then the method must return one of them, <code>null</code> is never an * acceptable return value.</li> * <li><b>XPath </b> <br> * XPath is the standard used to access all attributes (flat, nested, and multiple), via a single, * unified string. Using XPath to access attributes has the convenient side-benefit of making them * appear to be non-nested and non-multiple to callers with no awareness of XPath. This greatly * simplifies accessing and manipulating data. However, it does put extra burden on the implementers * of <code>FeatureType</code> to understand and correctly implement XPath pointers. Note that the * <code>Feature</code> object does not understand XPath at all and relies on implementors of this * interface to interpret XPath references. Fortunately, XPath is quite simple and has a clearly * written <a href="http://www.w3.org/TR/xpath">specification </a>.</li> * <li><b>Feature Creation </b> <br> * FeatureType also must provide methods for the creation of Features, as specified in * FeatureFactory. The creating FeatureType should check to see if the passed in objects validate * against its AttributeTypes, and if it does should return a new Feature.</li> * </ol> * <h2>Redesign Notes (feature-exp2)</h2> * The main design goal of this is to have FeatureType extend AttributeType. This allows us to * nesting of features much more nicely. We already are going in this direction, with the * FeatureAttributeType buried in DefaultAttribute. This is just making it explicit, so it works * with the complex objects GML can return a lot more sensible. So much of the work in this class is * figuring out what concepts are the same. Some stuff may need to be rethought a bit, as there are * a few subtle assumptions that we are working with flat files. We will revisit this when we * implement choice and multiplicity. * <ul> * <li>got rid of deprecated getNamespace() method that returned a string, replaced it with a URI * return. This has been deprecated for a bit, and was done out of a desire to keep backwards * compatibility with 2.0, but that mission failed, so we're just moving on. This change will break * a few things, but is a good one, people just need to update their client code a bit. * <li>Deprecated getTypeName() to be getName(). They are the same thing, would be nice to get rid * of getTypeName, but it's used super extensively. Though perhaps we could consider keeping it as a * convenience, a bit more explicit, but it seems like overkill. * <li>Updated comments of the AttributeType operations that are inhierited to say what they mean * in the context of a FeatureType. * </ul> * <h2>Redesign Notes (factory-hints)</h2> * The factory-hints design is finally coming through on the promiss of the great geotools factory * design. This design is actualy placing the factory system under application (rather than * 'default') control, as such it is really showing every last place where we did not follow our * architecture. * <ul> * Use Cases: * <li>Custom Feature: <br> * Application spedcifies the use of a custom feature implementation. This is used so an application * interface is supported by each and every feature created. * <li>optiomized coordinate storage <br> * LiteRenderer2 wants Shape2d specific CoordinateSequenceFactory used for all Geometry creation. * The point is to allow only the xy information to be retrieved, and in a format suitable for rapid * reprojection and coversion to a Java2D Shape. Any OpenGL (or Java3D) based renderer would also * run into this need. * </ul> * The second use case is interesting in that LiteRenderer2 will be using the Datastore at the same * time as other threads that want the normal coordinate sequence. So this is a per Query hint. * </ul> * <p> * Consequence: Since FeatureType is immutable, and CoordianteSequence is specified by the * GeometryFactory of the DefaultGeometryAttribute this implys that we have a per Query SchemaType. * </p> * <p> * It strikes me that this is a bad separation of concerns the "schema" should be exactly the same, * it is just the GeometryFactory that controls construction that is in the wrong spot. It should be * a hint, not attached to GeomtryAttributeType. * </p> * * @author Rob Hranac, VFNY * @author Chris Holmes, TOPP * @author David Zwiers, Refractions * @author Jody Garnett, Refractions * @source $URL$ * @version $Id$ * @see org.geotools.feature.Feature * @see org.geotools.feature.FeatureTypeFactory * @see org.geotools.feature.type.NestedAttributeType * @see org.geotools.feature.DefaultFeatureType * * @deprecated use {@link SimpleFeatureType}. */ public interface FeatureType extends SimpleFeatureType { // // XML Mapping Information // // Used for mapping Feature information to Geographical Markup Language, // /** * Gets the global schema namespace. * <p> * This is often used to record the schema prefix (not the URI) required when writing out this * Feature using GML. The supporting application will need to be able to start the GMLWriter off * with the correct URI information so everything makes sense. * </p> * <p> * The Registry interface provided by the data module provides an example of how to store * associate FeatureType and namespace information. Please note that you may not have duplicate * typeNames in the same Namespace. * </p> * * @return Namespace of schema */ URI getNamespace(); /** * Gets the type name for this schema. * <p> * In GML this must be the element name of the Feature. * </p> * * @return The name of this feature type. */ String getTypeName(); /** * Test to determine whether this FeatureType is descended from the given FeatureType. Think of * this relationship likes the "extends" relationship in java. * * @param nsURI The namespace URI to use. * @param typeName The typeName. * @return true if descendant, false otherwise. */ boolean isDescendedFrom(URI nsURI, String typeName); /** * A convenience method for calling <br> * <code><pre> * FeatureType f1; * FeatureType f2; * f1.isDescendedFrom(f2.getNamespace(), f2.getName()); * </pre></code> * <p> * Question: this method duplicates the information provided by getAncestors(). * </p> * * @param type The type to compare to. * @return true if descendant, false otherwise. */ boolean isDescendedFrom(FeatureType type); /** * Is this FeatureType an abstract type? * <p> * When true is returned instances of this Feature cannot be created, instead a child * FeatureType must use this FeatureType as its ancestor. * </p> * * @return true if abstract, false otherwise. */ boolean isAbstract(); /** * Obtain an array of this FeatureType's direct ancestors. * Implementors should return a non-null array (may be of length 0). * <p> * <ul> * <li>length 0 - a root FeatureType * <li>length 1 - singe inhieratance * <li>length 1+ - multiple inheiratance, order is not significant * </ul> * </p> * GetAncestors() indicates *just* the direct parents of this FeatureType. * It capures the inheirtance relationship from the OGC overview document. * </p> * <p> * Example Code:<pre><code> * public FeatureType getAncestors()} * return new FeatureType[]{ getSuper(), }; * } * </code></pre> * </p> * * @return An array of ancestors. */ FeatureType[] getAncestors(); /** * Return the direct supertype of this FeatureType. * <p> * This is a conviance method for FeatureType where only single * inheirtance is supported (as is the case with GML). * </p> * <p> * This method will return null for a root FeatureType. * </p> * @return Get the super type, or null for root. */ //FeatureType getSuper(); /** * Gets the default geometry AttributeType. * <p> * If the FeatureType has more one geometry it is up to the implementor to determine which * geometry is the default. If working with multiple geometries it is best to get the * attributeTypes and iterate through them, checking for instances of GeometryAttribtueType. * </p> * <p> * This should just be used a convenience method when it is known that the features do not have * multiple geometries. * </p> * * @return The attribute type of the default geometry, which will contain the position. * @deprecated use {@link #getPrimaryGeometry()}. */ //GeometryAttributeType getPrimaryGeometry(); /** * Gets the primary or default geometry AttributeType. * <p> * If the FeatureType has more one geometry it is up to the implementor to determine which * geometry is the default. If working with multiple geometries it is best to get the * attributeTypes and iterate through them, checking for instances of GeometryAttribtueType. * </p> * <p> * This should just be used a convenience method when it is known that the features do not have * multiple geometries. * </p> * <p> * This method is a replacement for {@link #getGeometryDescriptor()} in order * to resolve a naming conflict with the geoapi feature model. * </p> * * @return The attribute type of the default geometry, which will contain the position. * @since 2.4 */ GeometryAttributeType getGeometryDescriptor(); /** * The number of attribues defined by this schema. * <p> * This method to allows access to the complete schema as defined by this * FeatureType and its ancestors. * </p> * <p> * <ul> * Notes: * <li> * <li>for FeatureType with no super type this count value is the the * same as getAttributeTypes().length. * </p> * * @return number of distinct attributeTypes available, taking ancestors and taking overrides * into account. */ int getAttributeCount(); /** * Gets the attributeType at this xPath, if the specified attributeType does * not exist then <code>null</code> is returned. * <p> * Question: it is unclear how this interacts with the complete schema defined by this * FeatureType and its ancestors (in which a given xpath may refer to several AttributeTypes as * restrictions are applied. * </p> * <p> * Perhaps this method should be restricted to a FlatFeatureType? Or should have the option of * returning an array of matching AttributeType in order of inheiritence? * </p> * * @param xPath XPath pointer to attribute type. * @return AttributeType, or null if unavaialble */ AttributeType getAttributeType(String xPath); /** * Find the position of a given AttributeType. * <p> * Match is based on attribute type name, the resulting index * may be used with getAttributeType( index ). * </p> * @param type The type to search for. * @return -1 if not found, a zero-based index if found. */ int find(AttributeType type); /** * Find the position of an AttributeType which matches the given String. * <p> * This index may be used with getAttributeType( index ), the search space is the entire schema * defined by this FeatureType and its ancestors. * </p> * * @param attName the name to look for * @return -1 if not found, zero-based index otherwise */ int find(String attName); /** * Gets the schema attributeType at the specified index. * <p> * The index is specified with respect to the entire Schema (as defined by this FeatureType and * it's ancestors). * <p> * <ul> * The index value should not be used with either: * <li>FeatureType.getAttributeTypes()[index] - as it defines only attributes contributed by * this FeatureType * <li>Feature.getAttribute( index ) - as attributes order may or may not be in sequence * </ul> * </p> * * @param position a integer index into the complete schema represented by * this FeatureType and its ancestors * * @return the attribute type at the specified position */ AttributeType getAttributeType(int position); /** * AttributeTypes for this FeatureType, all attributes defined by this FeatureType * and its super types define schema for feature instances. * <p> * The provided array of AttributeTypes should be considered as adding to (or overriding) the * the AttribtueTypes defined by this FeatureTypes ancestors. * </p> * <p> * Note Well: Client code should not consider the index provided by the find( attName ) method * as a valid index into the returned array. * </p> * * @return Array of AttributeType describing this schema, array may be length 0, but should * not be null */ AttributeType[] getAttributeTypes(); // // Depreicated AttributeType handling code // // This is origional Geotools 2.0 api that is depricated and will // be removed as part of Geotools 2.2. // /** * This is only used twice in the whole geotools code base, and one of those is for a test, so * we're removing it from the interface. If getAttributeType does not have the AttributeType it * will just return null. Gets the number of occurrences of this attribute. * <p> * Question: the comment says we are removing this, but it is not depricated? And how the heck * can the number of occurances out of a boolean. * </p> * * @deprecated It seems this method is ill concieved, use getAttributeType( xpath ) != null as a * replacement * @param xPath XPath pointer to attribute type. * @return Number of occurrences. */ boolean hasAttributeType(String xPath); // // This is code that was available in Geotools 2.0 as part of the // FeatureFactory API, In geotools 2.1 we are providing a clear // separation between schema information and construction. // /** * Create a duplicate of the provided feature, must delegate to an appropriate FeatureFactory * create method. * <p> * The implementation is assumed to make use of AttributeType duplicate as required for a deep * copy. * </p> * * //@deprecated This method will be removed in 2.2, please use FeatureFactory obtained from FactoryFinder * @param feature * @return a deep copy of feature * @throws IllegalAttributeException */ Feature duplicate(Feature feature) throws IllegalAttributeException; /** * Creates a new feature, with a generated unique featureID. * <p> * Generating a FeatureID is less than ideal, as a FeatureID should be something * special about the "real world object" being modeled as a feature. * <p> * As an example: the "Effiel Tower" is a great feature id (there is only one) and we can * use that Feature ID in serveral systems: * <ul> * <li>In a tour guide FeatureTypes one which records (NAME, LOCATION, COST); and * <li>In a historical reference (NAME, LOCATION, HIEGHT, DATE, HISTORY) * </ul> * <p> * Explicitly a FeatureID should be persistant over time, and between systems. * <p> * The FeatureIDs "generated" by this method are generally created by a datasource. * This method is more for testing that doesn't need featureID. * </p> * <p> * Warning: This class does not follow the geotools guidelines of sepearting out * Interface from Factory, in geotools 2.3 there will be a formal FeatureFactory * allowing you to provide application specific FeatureImplementations as an orthogonal * concern to definition of type. * </p> * * @param attributes the array of attribute values * @return The created feature * @throws IllegalAttributeException if the FeatureType does not validate the attributes. */ Feature create(Object[] attributes) throws IllegalAttributeException; /** * Scheduled for removal in Geotools 2.2, please use FeatureFactory. * <p> * Creates a new feature, with the indicated featureID. * </p> * * @param attributes the array of attribute values. * @param featureID the feature ID. * @return the created feature. * @throws IllegalAttributeException if the FeatureType does not validate the attributes. */ Feature create(Object[] attributes, String featureID) throws IllegalAttributeException; /** * FeatureType check based on namespace, typeName, attributes and ancestors. * <p> * Conceptually FeatureType equality is supped to indicate an exact match based AttributeType * and Ancestors. The geotools models includes additional information of namespace * and typename. * </p> * <p> * As far as the geotools data model is concerned any FeatureType implementation should be able * to be subsituted for another. (An actually application may provided an implementation that * provdes tracking of metadata such as creation history, or support for additional interfaces). * </p> * <p> * Required implementation:<pre><code> * </code></pre> * A sample implementation is provided in FeatureTypes.equals( FeatureType, FeatureType ). * </p> * <p> * Questions: * <br>Q: You may wonder why namespace and typeName are not enought? * <br>A: Geotools often returns a "limitied" schema in response to a query where only a subset * of the attributes are requested. * <br>Q: Doesn't that still indicate the same schema? * <br>A: Yes it kind of should, a GML application (such as GeoServer) has to actually follow the * application schema and include attributes required by the schema (but not request by the query). * This library is more lax in its treatment, and expects you to uses isDecendedFrom as required. * </p> */ public boolean equals(Object arg0); /** * Hascode based on namespace, typeName, attributes and ancestors. * <p> * Hascode is always a matched set with an equals implementation, please see the javadocs * for equals for a detailed discussion. * </p> * @see java.lang.Object#hashCode() */ public int hashCode(); }