GeoTools : Feature API Overview

Feature API Overview (from 2.2M0)

On the next chapter, we're going to refer to some core GeoTools classes, so lets make a general overview of what those classes are and how they inter-relate.
This overview will be quick, since this document intended audience will be pretty familiar with the GeoTools architecture.

Feature related architectural layers

GeoTools is a library. A good one. As such, it has a layered architecture, from which we're focusing on its feature layer.
The package diagram at the left shows the dependencies between GeoTools layers with some direct meaning to the feature layer.
In short, the feature layer holds the very core GeoTools object model or, better said, feature model, in the generally accepted geospatial sense.
data is the GeoTools way of doing I/O of Features, streamed IO, regardless of the underlying persistence layer, for which it offers a complete plug-in architecture.
filter is the GeoTools implementation of the OGC Filter Encoding Implementation Specification, a construct used to describe constraints on properties of a feature class for the purpose of identifying a subset of feature instances to be operated upon.
All three packages make use of the factory classes for dynamic binding of implementations at runtime, allowing for third party implementations of the core GeoTools APIs.

Query Languages: Expression and XPath

The filter specification includes the concept of Expression, expressions opperate as a small Query language to access Feature content, in particular attribute access is required based on XPath expressions. This proves more interesting in the face of FeatureCollections where XPath expression can be used to extract content from child Features.

The Expression construct sees wide use and often serves as the "glue" between feature and other standards such as SLD. It is unlikely that any library code will directly access Feature content, by delegating to expression XPath support can be located in one layer of the library.

Feature API

So this is the Feature API.
Simply put, FeatureTypeBuilder allows to programatically build a FeatureType, and obtaining its (immutable) instance once ready. An AttributeTypeFactory may be used in the process of building a FeatureType, to create AttributeType instances and pass them to FeatureTypeBuilder.

FeatureType instances represents an actual feature class schema, consisting of a name, a namespace, and a set of (potentially complex) properties, where zero or more of them can be geospatially related (Geometry + Coordinate Reference System). As the attributes of a FeatureType, may be nested in many ways, the fetching of an attribute type from a FeatureType instance was conceived to be XPath aware from the initial API design. (info) Today, this design is being questioned. XPath type access to feature and featuretype members was actually never implemented, and (lightbulb) it could be good to leave the API cleaner (i.e. first depth level access only) and provide XPath like expression evaluation from outside, where it makes more sense, avoiding the burden of forcing implementors to deal with a rather complex expression language.
DefaultFeatureType is the general purpose FeatureType implementation.

The mentioned FeatureType properties, are indeed AttributeType s. AttributeType s have a name and a type, they may or may not allow null values, and may impose lower and upper bounds for the number of value occurrences, both of them defaulting to one occurrence. AttributeType s may have facets, which are a statement of the restrictions of the value space that attribute values must comply with in order to be acceptable, and provides the mechanisms to parse a value instance from an acceptable input object and to validate that such a value instance adheres to the type facets.

Finally, we need a placeholder for these attribute values. Feature instances provides such a place, and are uniquely identifiable inside the namespace of its FeatureType. A FeatureCollection is a Feature by itself, may have a FeatureType independently of the different schemas of the Features it holds, and provides for traversal and modification of its content by adhering to the java.util.Collection method contracts.

The notion of a SimpleFeature is drawn from the OGC's Simple Features for SQL specification - where a simple feature represents a single row in a database table. This extends beyond databases though, to flat files, for example.

SimpleFeature and SimpleFeatureType have born to allow the development of the complex attribute types support without breaking the pre-complex code, allowing all previous DataStore implementations and related code to continue making with the assumption that a Feature attribute has 1 cardinality and all its attributes are of a simple type.


You may be wondering what's going on with FeatureFactory: why it doesn't implements Factory and where is a FeatureFactory implementation? The point is that FeatureType used to implement FeatureFactory, but it no longer does, which is a good thing after all, since they're so different things. In the mean time, our core developers are thinking hard to find a way of not breaking existing code and still being able of getting rid of FeatureType::create and force using a FeatureFactory instead.

AttributeType class diagram

The AttributeType class hierarchy is perhaps the most important piece of study for this survey, since it shall hold most of the expressive power of the whole Feature API.
We already mentioned what the intent of AttributeType is.
PrimativeAttributeType was introduced to denote that an AttributeType realization is about a simple data type and to add the ability to have restrictions on a particular data primitive in a declarative manner, through the getRestriction():Filter method. Then, getRestriction() seems to have been promoted to the AttributeType superinterface. As it will be shown bellow, restrictions on complex data types refers to limiting the order and type of their child properties, and are modeled separatelly, (lightbulb) so it would make sense to eliminate getRestriction from AttributeType since the concept only applies to atomic data types.
GeometryAttributeType adds CRS knowledge for geometric attributes.
GeometricAttributeType, NumericAttributeType, TemporalAttributeType and TextualAttributeType specialize in parsing and validating geometric, numeric, temporal and textual literals respectivelly, relying on DefaultAttributeType for all the common behavior.
That's the "simple features" arm of the API. The complex one is represented by a set of AttributeType realizations each of on serves a specific complex construct, or XML Schema order indicator: choice, sequence, all.
All of them can contain a series of other AttributeTypes, either simple or complex, and gives different meaning as to how these contained types can be used.
ChoiceAttributeType maps to the choice construct in XML Schema, and is meant to represent a complex attribute type where the attribute value can be of one and only one of the types it holds.
ListAttributeType maps to the sequence construct in XML Schema, and is meant to represent a complex attribute type that holds value instances of the attribute types it holds, in the declared order.
SetAttributeType maps to the all construct in XML Schema, and is meant to represent a complex attribute type that holds value instances of the attribute types it holds, in any order, and where the multiplicity of its attributes is limited to 0..1.
FeatureAttributeType does not maps to a XML Schema construct, but to a GML feature Association property. It is conceptually different from a ListAttributeType in that it have to expose, among its own name, the name of the child FeatureType, to follow the GML Association rule.