I have been having a solid couple of months updating the geotools docs from a wiki - to sphinx. I thought I would share a couple of before and after examples with you.
If you are interested in keeping pace with this documentation effort you can review
my twitter feed; it seems that is all I use it for.
Versioned
Right off the bat we can see progress in the form of a latest and stable user guide matching a specific version of GeoTools. This will allow developers to grab a hold of the docs for the version of GeoTools they are using (I still get questions and bug fix requests from GeoTools 2.1 in 2003 ).
BEFORE
Wiki User Guide (examples ranging from GeoTools 2.1 through to 2.7)
AFTER
Latest User Guide (work in progress from 2.8-SNAPSHOT)
Stable User Guide (matching latest 2.7.0 release)
Diagrams
BEFORE
Our initial
meet the library page included this rather bright and cheerful graphic.
The problem was this graphic was drawn with viso (hardly an open source tool); more to the point it could not be updated as new functionality was added to the library.
We also had a few class diagrams done with random tools.
AFTER
The new welcome for
geotools overview offers a nice sedate graphic.
The interesting thing is it is now drawn with InkScape as an SVG file and included in the source code. So hopefully others can edit it.
I have also been able to commit
ObjectAid diagrams into the code base. These are live diagrams generated by dragging your source files onto the page from within eclipse. They also have an auto image setting so the diagrams can be updated as your classes change.
The up side of this is more diagrams in the docs; and that the diagrams will be up to date.
Code Examples
One of the big changes (and motivations) behind using sphinx rather than a wiki was the ability to use live code examples in the documentation.
BEFORE
Here is an example from the
wiki (Hint it does not actually compile):
private synchronized static FeatureSource
buildMemoryFeatureSource(FeatureCollection coll, String typename,
FeatureType currentFeatureType, AttributeType newTypes[]){
FeatureType ftState=null;
MemoryDataStore MStore=null;
try {
MStore = new MemoryDataStore();
//---- current attributes
AttributeType currentTypes[] = currentFeatureType.getAttributeTypes();
//---- new array of attributes = current array+ new attributes
AttributeType typesNew[] = new
AttributeType[currentTypes.length+newTypes.length];
for(int i=0;i<currentTypes.length;i++){
typesNew[i] = currentTypes[i];
}
for(int i=0;i<newTypes.length;i++){
typesNew[currentTypes.length+i] = newTypes[i];
}
ftState = FeatureTypeFactory.newFeatureType(typesNew, typename);
MStore.createSchema(ftState);
Iterator iterator = coll.iterator();
FeatureCollection newColl = FeatureCollections.newCollection();
Feature feature, newFeature;
Object[] objs;
try {
for( int count=0; iterator.hasNext(); count++) {
feature = (Feature) iterator.next();
objs = new
Object[feature.getNumberOfAttributes()+newTypes.length];
for (int i = 0; i < feature.getNumberOfAttributes();
i++) {
objs[i] = feature.getAttribute(i);
}
newFeature = ftState.create( objs, feature.getID());
newColl.add(newFeature);
}
} finally {
coll.close( iterator );
}
MStore.addFeatures(newColl);
return MStore.getFeatureSource(typename);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
AFTER
And
after we have something that we know compiles and has had the eclipse auto formatter take a run at it for readability.
SimpleFeatureSource alter(SimpleFeatureCollection collection, String typename,
SimpleFeatureType featureType, final List<AttributeDescriptor> newTypes) {
try {
// Create target schema
SimpleFeatureTypeBuilder buildType = new SimpleFeatureTypeBuilder();
buildType.init(featureType);
buildType.setName(typename);
buildType.addAll(newTypes);
final SimpleFeatureType schema = buildType.buildFeatureType();
// Configure memory datastore
final MemoryDataStore memory = new MemoryDataStore();
memory.createSchema(schema);
collection.accepts(new FeatureVisitor() {
public void visit(Feature feature) {
SimpleFeatureBuilder builder = new SimpleFeatureBuilder(schema);
builder.init((SimpleFeature) feature);
for (AttributeDescriptor descriptor : newTypes) {
builder.add(DataUtilities.defaultValue(descriptor));
}
SimpleFeature newFeature = builder.buildFeature(feature.getIdentifier().getID());
memory.addFeature(newFeature);
}
}, null);
return memory.getFeatureSource(typename);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Ease of Use
Another obvious change as I go through the docs is the strides made to make development easier. From utility classes such as DataUtilities, JTS and CRS through to helpful base classes.
BEFORE: AbstractDataStore
This class was the base for our initial GeoTools 2.0 DataStore API; as such it grew all kinds of interesting tricks as it came to be all things to all people.
I have left off several classes from the above diagram to protect the innocent.
AFTER: ContentDataStore
Justin and I made a new start with ContentDataStore focused on only asking developers to do the bare minimum needed to support their data format.
And handling all the DataStore, FeatureSource / FeatureStore / FeatureLocking, FeatureCollection/FeatureIterator, FeatureReader / FeatureWriter stuff for them with no additional subclassing.
Details only a developer could love:
- Previously AbstractDataStore was the subject of a tutorial on the wiki; that carefully walks you through creating six classes needed to read and write a simple text file.
- We can get a working implementation in four classes this time out and a lot less code.
- BEFORE: Content was handled through a careful applied series of "wrappers" (ie 30 lines of boilerplate code you had to cut and paste exactly right)
- AFTER: configure a few settings describing what your format supports out of the box (such as filtering). GeoTools will proceed to do the rest of the work for you (transactions, locking, reprojection).