org.geotools.data interface scratchpad - STEMLab/geotools GitHub Wiki
The e-mails discussing the various data interfaces (DataStore, FeatureCollection, etc) get pretty lengthy. Hopefully this page can serve as a summary of what the interfaces might look like with the most current suggestions.
Note that Java generic syntax is used below in several places (i.e. List<QName>). This is used for clarity of writing, but may not actually be used in the "real" interfaces.
(Note: This was started by Chris Dillard in hopes that someone with a little more time would come
along and finish filling things in...)
(Comments inline from James Macgill, marked JRM)
interface DataStore {
// Gets a list of all the names of the types held in this DataStore.
List<QName> getTypeNames();
// Gets all features of the given type
FeatureCollection getFeatures(QName type);
// Gets all features of the given type that pass some Filter
FeatureCollection getFeatures(QName type, Filter f);
// Gets features of the given type that pass some query.
// This allows for retrieving only a subset of the attributes (and
// may allow for reprojection)
FeatureCollection getFeatures(QName type, Query q);// should/could the type be part of the
// query (JRM)
// Shortcut for getting the FeatureCollection then calling setTransaction(t)
FeatureCollection getFeatures(QName type, Query q, Transaction t);
}
interface Feature {
FeatureType getFeatureType();
FeatureCollection getParent(); //Back pointer is v.important. (JRM)
// getBounds() can return null if Feature has no geometry
Envelope getBounds();
String getID();
Object getAttribute(String path) throws IllegalAttributeException;
Object getAttribute(int index) throws IndexOutOfBoundsException;
void setAttribute(String path, Object value) throws IllegalAttributeException;
void setAttribute(int index, Object value) throws IndexOutOfBoundsException;
}
interface FeatureCollection extends Feature, Collection {
// Accessor methods, from Collection
// Will always return FeatureIterator, shown below.
Iterator<Feature> iterator();
// DZ - add a throws OperationNotSupported?
// CSD - Under what circumstances could these operations not be supported?
// DZ - the toArray() function may not be supported for large dataset. Also optionally returning null works.
Object [] toArray();
Object [] toArray(Object [] buffer);
// Size methods, from Collection
boolean isEmpty();
// May return -1 if size is not known (streaming)
int size();
// Feature containment checking, from Collection
boolean contains(Object o);
boolean containsAll(Collection c);
// Modification methods from Collection. All may throw UnsupportedOperationException
// This is in line with the Collections 'Unmodifiable' approach. (JRM)
boolean add(Object o);
boolean addAll(Collection c);
void clear();
boolean remove(Object o);
boolean removeAll(Collection c);
boolean retainAll(Collection c);
// Do we need a close() operation?
void close() throws IOException; // I don't think so, I don't see how a FeatureCollection
// could ever be open or closed, it just is. the class
// returned by iterattor() would have to handle this. (JRM)
// DZ - hmm, very useful for many datastores, we can't rely on dispose to be executed in a
// DZ - timely manner which could cause connection issues
// CSD - It seems FeatureCollection represents the result of a specific query, so you will
// CSD - need a close() operation to clean up.
// If the add() methods are to work, we'll need a transaction somehow:
void setTransaction(Transaction t);
Transaction getTransaction();
// The above is true iif modifications to a FeatureCollection are imidatly reflected in the
// orignating DataStore, this may or may not be the case. Needs some thought. (JRM)
// Listener methods
public void addFeatureListener(FeatureListener fl);
public void removeFeatureListener(FeatureListener fl);
}
interface FeatureType {
// Include all the same stuff that's in FeatureType now.
// Also include the following:
// Returns true if Features of this type can be cast to FeatureCollection.
boolean isCollection();
// If isCollection() returns true, this method returns a non-empty
// list of FeatureTypes that indicates what types of Features can be
// elements of the collection.
List<FeatureType> getChildTypes();
}
interface QName {
// Get the namespace for your feature.
public URI getNamespaceURI();
// Get the name (without namespace or prefix)
public String getLocalName();
// This can return null if not known or data source doesn't care.
// Note that this only applies when the features are encoded as XML.
public String getPreferredPrefix();
}
As an example, suppose we have some feature xml that looks like this:
<xyz:MajorRoads xmlns:xyz="http://www.foo.com/data/majorroads">
...
</xyz:MajorRoads>
For a QName describing this Feature, getNamespaceURI()
would return
"http://www.foo.com/data/majorroads"
, getLocalName()
would return "MajorRoads"
, and
getPreferredPrefix()
could return "xyz"
.
It seems like we need some way of calling "close" on an iterator. Relying on garbage collection (and
implementing finalize()
) is a bad idea.
CSD - Do we want to extend ListIterator? I suspect not... Although nothing prevents a given DataStore from returning one if it can easily seek.
interface FeatureIterator extends Iterator {
// For clarity, here are the methods from Iterator:
boolean hasNext();
Object next();
void remove(); // Throws UnsuppOpException
// And here's the reason for this interface to exist:
public void close() throws IOException;
}
interface FeatureListener {
public void featuresAdded(FeatureEvent e);
public void featuresRemoved(FeatureEvent e);
public void featuresChanged(FeatureEvent e);
}
class FeatureEvent extends java.util.EventObject {
// IDs of the features that were affected
private List<String> fids;
public FeatureEvent(FeatureCollection source, List<String> fids) {
super(source);
}
public List<String> getFeatureIDs() {
return fids;
}
// Synonym for EventObject.getSource(), but does the cast for you
public FeatureCollection getFeatureCollection() {
return (FeatureCollection) getSource();
}
}
Examples of using the interfaces in common situations.
public class Test {
public static void main(String [] args) {
DataStore ds = ... ;
FeatureCollection fc = null;
FeatureIterator fi = null;
try {
fc = ds.getFeatures(new QName("Roads"));
fi = (FeatureIterator) fc.iterator();
while (fi.hasNext()) {
Feature f = (Feature) fi.next();
doStuffWithFeature(f);
}
}
finally {
if (fi != null) fi.close();
if (fc != null) fc.close();
}
}
}