1.架构设计
OGC 规范对空间矢量数据的框架进行了设计,GeoTools 对其进行了实现。其中的 DataStore 可以近似理解成关系数据库中的个数据库实例,FeatureSource 可以近似理解成关系数据库中的一张表。
DataAccess 接口主要对空间要素类型的相关信息的构建、读取、更新、清除等操作进行了设定。DataStore 接口直接继承了 DataAccess 接口,DataAccess 接口主要定义了数据源的基本行为,如新建、更改、删除等,将一整套 SimpleFeature 的数据模型进行了嵌入可以看到所有的数据转换格式已经从上层的泛型具象成了 SimpleFeature以及 SimpleFeatureType。除此以外,DataStore 也指定了空间矢量数据的读写方法以及相关的函数。FeatureSource (可通过DataStore获取)和 SimpleFeatureSource 则是与具体的 SimpleFeatureType 绑定的数据结构,用户可以通过其子类对表,直接进行查询和写入操作。
public interface DataAccess<T extends FeatureType, F extends Feature> {// 获取数据信息ServiceInfo getInfo();// 新建数据void createSchema(T featureType) throws IOException;// 更新数据字段信息void updateSchema(Name typeName, T featureType) throws IOException;// 删除数据void removeSchema(Name typeName) throws IOException;// 获取数据名称List<Name> getNames() throws IOException;// 获取数据字段信息T getSchema(Name name) throws IOException;// 获取数据源FeatureSource<T, F> getFeatureSource(Name typeName) throws IOException;// 释放数据连接void dispose();}
2.DataStore
DataStore 提供了较为完整的读写功能,熟悉 Java 的同学甚至可以将其理解成一个类似于JDBC 的连接空间数据的驱动程序。
DataStore 是主要用于访问和存储矢量格式的空间数据的引擎。矢量数据的数据格式有很多种。GeoTools 支持如 Shapefile、数据库等的接入其支持的数据源种类有很多种,例如地理信息系统行业常用的 PostGIS、时空数据领域使用到的 GeoMesa、新型的 GeoPackage 等。在支持这些数据源时,GeoTools 提供了统一的 DataStore 访问接口,如代码清单 5-2 所示。用户只需要实现这个接口,就能够针对特定的数据源进行相应的扩展。
public interface DataStore extends DataAccess<SimpleFeatureType, SimpleFeature> {// 更新SimpleFeatureType 结构信息void updateSchema(String typeName, SimpleFeatureType featureType) throws IOException;// 删除SimpleFeatureType void removeSchema(String typeName) throws IOException;// 获取SimpleFeatureType 名称String[] getTypeNames() throws IOException;// 获取SimpleFeatureType 对象SimpleFeatureType getSchema(String typeName) throws IOException;// 获取FeatureSource对象SimpleFeatureSource getFeatureSource(String typeName) throws IOException;// 获取查询结果SimpleFeatureSource getFeatureSource(Name typeName) throws IOException;// 获取查询结果FeatureReader<SimpleFeatureType, SimpleFeature> getFeatureReader(Query query, Transaction transaction) throws IOException;// 获取写入对象FeatureWriter<SimpleFeatureType, SimpleFeature> getFeatureWriter(String typeName, Filter filter, Transaction transaction) throws IOException;}
DataStore 所对应的是比 SimpleFeatureType 更上层的概念,对应关系数据库中的 database 的概念,用户可以利用 DataStore 对多个SimpleFeatureType 进行控制和管理。从上述代码清单中可以看到DataStore 内部规定了 SimpleFeatureType 的更新、删除和获取操作,也实现了针对 SimpleFeatureType 的读写操作。
3. FeatureSource
FeatureSource 与 DataStore 相比,它的操作粒度更细
public interface FeatureSource<T extends FeatureType, F extends Feature> {// 获取SimpleFeatureType 名称Name getName();// 获取SimpleFeatureType 信息ResourceInfo getInfo();// 获取所属DataStore对象DataAccess<T, F> getDataStore();// 获取查询容量QueryCapabilities getQueryCapabilities();void addFeatureListener(FeatureListener listener);void removeFeatureListener(FeatureListener listener);// 获取要素信息FeatureCollection<T, F> getFeatures(Filter filter) throws IOException;FeatureCollection<T, F> getFeatures(Query query) throws IOException;FeatureCollection<T, F> getFeatures() throws IOException;// 获取结构信息 T getSchema();// 获取边界信息 ReferencedEnvelope getBounds() throws IOException;ReferencedEnvelope getBounds(Query query) throws IOException;// 获取数据条数int getCount(Query query) throws IOException;// 获取支持的Hintpublic Set<RenderingHints.Key> getSupportedHints();
}
4. FeatureStore
FeatureStare 是 FeatureSource 的一个子接口,它针对数据本身进行了一些新的设定。
public interface FeatureStore<T extends FeatureType, F extends Feature>extends FeatureSource<T, F> {// 插入数据 List<FeatureId> addFeatures(FeatureCollection<T, F> featureCollection) throws IOException;// 删除数据void removeFeatures(Filter filter) throws IOException;// 更改数据void modifyFeatures(Name[] attributeNames, Object[] attributeValues, Filter filter)throws IOException;void modifyFeatures(AttributeDescriptor[] type, Object[] value, Filter filter)throws IOException;void modifyFeatures(Name attributeName, Object attributeValue, Filter filter)throws IOException;void modifyFeatures(AttributeDescriptor type, Object value, Filter filter) throws IOException;// 流式插入数据 void setFeatures(FeatureReader<T, F> reader) throws IOException;void setTransaction(Transaction transaction);Transaction getTransaction();
}
从代码中可以看出,FeatureStore 对数据操作和事务操作进行了细化。在数据操作方面,增加了插入数据、删除数据、更新数据的相关内容在事务操作方面,用户可以配置事务信息,但是由于 GeoTools 目前并没有将重点放在事务上,因此现在只支持默认 (Default) 和自动提交 (AutoCommit) 两种事务的模式。
5.SimpleFeature
SimpleFeature 在 GeoTools 内部就是具体的数据条目,可类比为关系数据库中的一条记录。早期 OGC 对空间要素 (Geometry Feature) 有过非常详细的设定,但是这样的设定过于复杂,以致行业内产生了简化要素(Simple Feature) 这种设定,这也是 [Simple] 的由来。GeoTools 内部采用 SimpleFeature 作为自己的空间数据结构。
public interface SimpleFeature extends Feature {String getID();// 获取 SimpleFeatureType SimpleFeatureType getType();SimpleFeatureType getFeatureType();// 获取所有属性List<Object> getAttributes();// 设置属性void setAttributes(List<Object> values);void setAttributes(Object[] values);Object getAttribute(String name);void setAttribute(String name, Object value);Object getAttribute(Name name);void setAttribute(Name name, Object value);Object getAttribute(int index) throws IndexOutOfBoundsException;void setAttribute(int index, Object value) throws IndexOutOfBoundsException;// 获取属性个数 int getAttributeCount();// 获取默认空间数据 Object getDefaultGeometry();// 设置默认空间数据void setDefaultGeometry(Object geometry);
}
6. SimpleFeatureType
SimpleFeatureType 是 GeoTools 内部用来对 SimpleFeature 进行数据结构约束的数据结构,它可以类比为关系数据库的表结构。
public interface SimpleFeatureType extends FeatureType {// 获取SimpleFeatureType 名称String getTypeName();// 获取所有属性的描述器 List<AttributeDescriptor> getAttributeDescriptors();// 根据属性名称获取对应的属性描述器AttributeDescriptor getDescriptor(String name);AttributeDescriptor getDescriptor(Name name);AttributeDescriptor getDescriptor(int index) throws IndexOutOfBoundsException;// 获取属性个数 int getAttributeCount();// 获取所有属性的数据类型 List<AttributeType> getTypes();// 根据名称筛选属性类型 AttributeType getType(String name);AttributeType getType(Name name);AttributeType getType(int index) throws IndexOutOfBoundsException;// 获取单个属性的索引 int indexOf(String name);int indexOf(Name name);
}
从代码中,我们可以看出,SimpleFeatureType 内部主要是对自身的属性以及属性的描述器类 Attribute Descriptor 进行管理的配置和获取方法的实现,用户在使用过程中,可以比较方便地获取到相关的信息
7. FeatureCollection
FeatureCollection 是 GeoTools 参考 Java 语言的集合类(Collection)设计的存储 Feature 对象的集合类。为了更好地操作空间数据对象,FeatureCollection 在使用上与 Java 集合类主要有两点不同。第-点是 FeatureCollection 的迭代器 (lterator) 必须在使用完毕后进行显式的关闭操作,才能避免内存泄漏。第二点是存储在同一个FeatureCollection 中的对象具有相同的 SimpleFeatureType。
public interface FeatureCollection<T extends FeatureType, F extends Feature> {// 迭代器,使用完毕必须关闭 FeatureIterator<F> features();// 获取SimpleFeatureType T getSchema();/** ID used when serializing to GML */String getID();// 数据访问方式 void accepts(FeatureVisitor visitor, ProgressListener progress) throws IOException;// 针对FeatureCollection 查询子集合 public FeatureCollection<T, F> subCollection(Filter filter);public FeatureCollection<T, F> sort(SortBy order);// 获取最小外接矩形ReferencedEnvelope getBounds();// 是否包含指定元素boolean contains(Object o);boolean containsAll(Collection<?> o);// 是否为空boolean isEmpty();
}
public interface SimpleFeatureCollectionextends FeatureCollection<SimpleFeatureType, SimpleFeature> {// 迭代器,使用完毕后必须关闭public SimpleFeatureIterator features();public SimpleFeatureCollection subCollection(Filter filter);public SimpleFeatureCollection sort(SortBy order);
}
值得强调的是,FeatureCollection 并不是将数据全部加载到内存中的传统集合类,由于空间数据通常数据量较大,一味地加载到内存中通常会导致内存超限。因此 GeoTools 在实现 FeatureCollection 时使用流式数据模型,尽量减少内存的使用量,也因此造成 FeatureCollection 的迭代器在使用完毕后必须关闭的问题
由于 Java 泛型类在类型定义上比较几余,在处理由 SimpleFeature 和SimpleFeatureType 构成的 FeatureCollection 时必须不断地定义FeatureCollection<SimpleFeatureType,Simple Feature>,因此GeoTools 设计了 SimpleFeatureCollection 语法糖来帮助用户更好地使用Feature Collection。